Re: [PATCH v15 2/2] PCI: microchip: Add host driver for Microchip PCIe controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 19, 2020 at 04:33:10PM +0000, Daire.McNamara@xxxxxxxxxxxxx wrote:

> + *	pcie-altera.c
> + */

Add a blank line here.

> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/module.h>

> +static struct mc_port *port;

This file scope item is not ideal.  It might work in your situation if
you can never have more than one device, but it's not a pattern we
want other people to copy.

I think I sort of see how it works:

  mc_pci_host_probe
    pci_host_common_probe
      ops = of_device_get_match_data()              # mc_ecam_ops
      gen_pci_init(..., ops)
        pci_ecam_create(..., ops)
	  ops->init                                 # mc_ecam_ops.init
	    mc_platform_init(pci_config_window *)
	      port = devm_kzalloc(...)              # initialized
    mc_setup_windows
      bridge_base_addr = port->axi_base_addr + ...  # used

And you're using the file scope "port" because mc_platform_init()
doesn't have a pointer to the platform_device.  But I think this
abuses the pci_ecam_ops design to do host bridge initialization that
it is not intended for.

I'd suggest copying the host bridge init design from somewhere else.
tango_pcie_probe() also calls pci_host_common_probe(), so maybe that's
a good place.  But the fact that it's the *only* such caller makes me
think it might not be the best thing to copy.

Rob has been working in this area and probably has better insight.

> +static void mc_pcie_isr(struct irq_desc *desc)
> +{
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct mc_port *port = irq_desc_get_handler_data(desc);
> +	struct device *dev = port->dev;
> +	struct mc_msi *msi = &port->msi;
> +	void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE1_BRIDGE_ADDR;
> +	unsigned long status;
> +	unsigned long intx_status;
> +	unsigned long msi_status;
> +	u32 bit;
> +	u32 virq;
> +
> +	/*
> +	 * The core provides a single interrupt for both INTx/MSI messages.
> +	 * So we'll read both INTx and MSI status.
> +	 */
> +	chained_irq_enter(chip, desc);
> +
> +	status = readl_relaxed(bridge_base_addr + MC_ISTATUS_LOCAL);

readl_relaxed() is defined to return a u32, so you might as well
declare "status" and related things as u32 instead of "unsigned long".

> +static void mc_pcie_enable_msi(struct mc_port *port, void __iomem *base)
> +{
> +	struct mc_msi *msi = &port->msi;
> +	u32 cap_offset = MC_MSI_CAP_CTRL_OFFSET;
> +

Remove this blank line.  We usually just separate the automatic
variables from the code with a blank line.

> +	u16 msg_ctrl = readw_relaxed(base + cap_offset + PCI_MSI_FLAGS);

> +static void mc_mask_intx_irq(struct irq_data *data)
> +{
> +	struct mc_port *port = irq_data_get_irq_chip_data(data);
> +	void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE1_BRIDGE_ADDR;
> +	unsigned long flags;
> +	u32 mask, val;
> +
> +	mask = PCIE_LOCAL_INT_ENABLE;
> +	raw_spin_lock_irqsave(&port->intx_mask_lock, flags);
> +	val = readl_relaxed(bridge_base_addr + MC_IMASK_LOCAL);
> +	val &= ~mask;

Why bother with "mask" here?  It's only used once; just use
PCIE_LOCAL_INT_ENABLE directly.

> +	writel_relaxed(val, bridge_base_addr + MC_IMASK_LOCAL);
> +	raw_spin_unlock_irqrestore(&port->intx_mask_lock, flags);
> +}
> +
> +static void mc_unmask_intx_irq(struct irq_data *data)
> +{
> +	struct mc_port *port = irq_data_get_irq_chip_data(data);
> +	void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE1_BRIDGE_ADDR;
> +	unsigned long flags;
> +	u32 mask, val;
> +
> +	mask = PCIE_LOCAL_INT_ENABLE;
> +	raw_spin_lock_irqsave(&port->intx_mask_lock, flags);
> +	val = readl_relaxed(bridge_base_addr + MC_IMASK_LOCAL);
> +	val |= mask;

Here also.

> +static int mc_platform_init(struct pci_config_window *cfg)
> +{
> +	struct device *dev = cfg->parent;
> +	struct platform_device *pdev = to_platform_device(dev);
> +	void __iomem *bridge_base_addr;
> +	void __iomem *ctrl_base_addr;
> +	int ret;
> +	u32 irq;
> +	u32 val;
> +
> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +	port->dev = dev;
> +
> +	port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
> +	if (IS_ERR(port->axi_base_addr))
> +		return PTR_ERR(port->axi_base_addr);
> +
> +	bridge_base_addr = port->axi_base_addr + MC_PCIE1_BRIDGE_ADDR;
> +	ctrl_base_addr = port->axi_base_addr + MC_PCIE1_CTRL_ADDR;
> +
> +	port->msi.vector_phy = MC_MSI_ADDR;
> +	port->msi.num_vectors = MC_NUM_MSI_IRQS;
> +	ret = mc_pcie_init_irq_domains(port);
> +	if (ret) {
> +		dev_err(dev, "failed creating IRQ domains\n");
> +		return ret;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {

platform_get_irq() returns "int".  You declared "irq" as "u32" above,
so this check for failure won't work correctly.

> +		dev_err(dev, "unable to request IRQ%d\n", irq);
> +		return -ENODEV;
> +	}




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux