]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'pci-v4.4-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Dec 2015 17:26:06 +0000 (09:26 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Dec 2015 17:26:06 +0000 (09:26 -0800)
Pull PCI fixes from Bjorn Helgaas:
 "These are more fixes I'd like to have in v4.4.  Several for the Altera
  driver added for v4.4, and one for an MSI domain problem that affects
  several arm64 platforms:

  MSI:
   - Only use the generic MSI layer when domain is hierarchical (Marc
     Zyngier)

  Altera host bridge driver:
   - Fix loop in tlp_read_packet() (Dan Carpenter)
   - Fix Requester ID for config accesses (Ley Foon Tan)
   - Check TLP completion status (Ley Foon Tan)
   - Fix error when INTx is 4 (Ley Foon Tan)"

* tag 'pci-v4.4-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  PCI: altera: Fix error when INTx is 4
  PCI: altera: Check TLP completion status
  PCI: altera: Fix Requester ID for config accesses
  PCI: altera: Fix loop in tlp_read_packet()
  PCI/MSI: Only use the generic MSI layer when domain is hierarchical

drivers/pci/host/pcie-altera.c
drivers/pci/msi.c

index e5dda38bdde5e1735a50b4de9fcd2cd6307d13c5..99da549d5d06a067b58d3bbe08c39041a9d90605 100644 (file)
 #define TLP_CFG_DW2(bus, devfn, offset)        \
                                (((bus) << 24) | ((devfn) << 16) | (offset))
 #define TLP_REQ_ID(bus, devfn)         (((bus) << 8) | (devfn))
+#define TLP_COMP_STATUS(s)             (((s) >> 12) & 7)
 #define TLP_HDR_SIZE                   3
 #define TLP_LOOP                       500
+#define RP_DEVFN                       0
 
 #define INTX_NUM                       4
 
@@ -166,34 +168,41 @@ static bool altera_pcie_valid_config(struct altera_pcie *pcie,
 
 static int tlp_read_packet(struct altera_pcie *pcie, u32 *value)
 {
-       u8 loop;
+       int i;
        bool sop = 0;
        u32 ctrl;
        u32 reg0, reg1;
+       u32 comp_status = 1;
 
        /*
         * Minimum 2 loops to read TLP headers and 1 loop to read data
         * payload.
         */
-       for (loop = 0; loop < TLP_LOOP; loop++) {
+       for (i = 0; i < TLP_LOOP; i++) {
                ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
                if ((ctrl & RP_RXCPL_SOP) || (ctrl & RP_RXCPL_EOP) || sop) {
                        reg0 = cra_readl(pcie, RP_RXCPL_REG0);
                        reg1 = cra_readl(pcie, RP_RXCPL_REG1);
 
-                       if (ctrl & RP_RXCPL_SOP)
+                       if (ctrl & RP_RXCPL_SOP) {
                                sop = true;
+                               comp_status = TLP_COMP_STATUS(reg1);
+                       }
 
                        if (ctrl & RP_RXCPL_EOP) {
+                               if (comp_status)
+                                       return PCIBIOS_DEVICE_NOT_FOUND;
+
                                if (value)
                                        *value = reg0;
+
                                return PCIBIOS_SUCCESSFUL;
                        }
                }
                udelay(5);
        }
 
-       return -ENOENT;
+       return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
 static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers,
@@ -233,7 +242,7 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn,
        else
                headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1);
 
-       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
                                        TLP_READ_TAG, byte_en);
        headers[2] = TLP_CFG_DW2(bus, devfn, where);
 
@@ -253,7 +262,7 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
        else
                headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1);
 
-       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
                                        TLP_WRITE_TAG, byte_en);
        headers[2] = TLP_CFG_DW2(bus, devfn, where);
 
@@ -458,7 +467,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
        struct device_node *node = dev->of_node;
 
        /* Setup INTx */
-       pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM,
+       pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM + 1,
                                        &intx_domain_ops, pcie);
        if (!pcie->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
index 53e463244bb7e35ac368ff088a4976c2153fce3d..7eaa4c87fec71c8dd792ccffc919b322711d91dd 100644 (file)
@@ -54,7 +54,7 @@ static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        struct irq_domain *domain;
 
        domain = pci_msi_get_domain(dev);
-       if (domain)
+       if (domain && irq_domain_is_hierarchy(domain))
                return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
 
        return arch_setup_msi_irqs(dev, nvec, type);
@@ -65,7 +65,7 @@ static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
        struct irq_domain *domain;
 
        domain = pci_msi_get_domain(dev);
-       if (domain)
+       if (domain && irq_domain_is_hierarchy(domain))
                pci_msi_domain_free_irqs(domain, dev);
        else
                arch_teardown_msi_irqs(dev);