@@ -134,7 +134,7 @@ struct mtk_pcie_port;
/**
* struct mtk_pcie_soc - differentiate between host generations
- * @has_msi: whether this host support MSI interrupt or not
+ * @has_msi: whether this host supports MSI interrupts or not
* @ops: pointer to configuration access functions
* @startup: pointer to controller setting functions
* @setup_irq: pointer to initialize IRQ functions
@@ -439,44 +439,51 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
return 0;
}
-static int mtk_pcie_assign_msi(struct mtk_pcie_port *port)
+static int mtk_pcie_msi_alloc(struct mtk_pcie_port *port)
{
- int pos;
+ int msi;
- pos = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM);
- if (pos < MTK_MSI_IRQS_NUM)
- set_bit(pos, port->msi_irq_in_use);
+ msi = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM);
+ if (msi < MTK_MSI_IRQS_NUM)
+ set_bit(msi, port->msi_irq_in_use);
else
return -ENOSPC;
- return pos;
+ return msi;
+}
+
+static void mtk_pcie_msi_free(struct mtk_pcie_port *port, unsigned long hwirq)
+{
+ clear_bit(hwirq, port->msi_irq_in_use);
}
static int mtk_pcie_msi_setup_irq(struct msi_controller *chip,
- struct pci_dev *pdev,
- struct msi_desc *desc)
+ struct pci_dev *pdev, struct msi_desc *desc)
{
struct mtk_pcie_port *port;
struct msi_msg msg;
+ unsigned int irq;
int hwirq;
- u32 irq;
port = mtk_pcie_find_port(pdev->bus, pdev->devfn);
if (!port)
return -EINVAL;
- chip->dev = &pdev->dev;
- hwirq = mtk_pcie_assign_msi(port);
+ hwirq = mtk_pcie_msi_alloc(port);
if (hwirq < 0)
return hwirq;
irq = irq_create_mapping(port->msi_domain, hwirq);
- if (!irq)
+ if (!irq) {
+ mtk_pcie_msi_free(port, hwirq);
return -EINVAL;
+ }
+
+ chip->dev = &pdev->dev;
irq_set_msi_desc(irq, desc);
- /* MT2712/MT7622 only support 32 bit MSI address */
+ /* MT2712/MT7622 only support 32-bit MSI addresses */
msg.address_hi = 0;
msg.address_lo = lower_32_bits((u64)(port->base + PCIE_MSI_VECTOR));
msg.data = hwirq;
@@ -497,10 +504,8 @@ static void mtk_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
if (!port)
return;
- if (!test_bit(hwirq, port->msi_irq_in_use))
- dev_err(&pdev->dev, "trying to free unused MSI#%d\n", irq);
- else
- clear_bit(hwirq, port->msi_irq_in_use);
+ irq_dispose_mapping(irq);
+ mtk_pcie_msi_free(port, hwirq);
}
static struct msi_controller mtk_pcie_msi_chip = {
@@ -529,16 +534,26 @@ static const struct irq_domain_ops msi_domain_ops = {
.map = mtk_pcie_msi_map,
};
-static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
+static int mtk_pcie_enable_msi(struct mtk_pcie_port *port)
{
u32 val;
+ port->msi_domain = irq_domain_add_linear(node, MTK_MSI_IRQS_NUM,
+ &msi_domain_ops,
+ &mtk_pcie_msi_chip);
+ if (!port->msi_domain) {
+ dev_err(dev, "failed to create MSI IRQ domain\n");
+ return -ENOMEM;
+ }
+
val = lower_32_bits((u64)(port->base + PCIE_MSI_VECTOR));
writel(val, port->base + PCIE_IMSI_ADDR);
val = readl(port->base + PCIE_INT_MASK);
val &= ~MSI_MASK;
writel(val, port->base + PCIE_INT_MASK);
+
+ return 0;
}
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -559,6 +574,7 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
{
struct device *dev = port->pcie->dev;
struct device_node *pcie_intc_node;
+ int err;
/* Setup INTx */
pcie_intc_node = of_get_next_child(node, NULL);
@@ -574,16 +590,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
return -ENODEV;
}
- /* Setup MSI */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
- port->msi_domain = irq_domain_add_linear(node, MTK_MSI_IRQS_NUM,
- &msi_domain_ops,
- &mtk_pcie_msi_chip);
- if (!port->msi_domain) {
- dev_err(dev, "failed to get MSI IRQ domain\n");
- return -ENODEV;
- }
- mtk_pcie_enable_msi(port);
+ err = mtk_pcie_enable_msi(port);
+ if (err < 0)
+ return err;
}
return 0;