Merge branch 'pci/virtualization'
authorBjorn Helgaas <bhelgaas@google.com>
Thu, 2 Sep 2021 19:56:43 +0000 (14:56 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 2 Sep 2021 19:56:43 +0000 (14:56 -0500)
- Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms (Wasim Khan)

- Add ACS quirks for Cavium multi-function devices (George Cherian)

- Enforce pci=noats with Transaction Blocking (Alex Williamson)

* pci/virtualization:
  PCI/ACS: Enforce pci=noats with Transaction Blocking
  PCI: Add ACS quirks for Cavium multi-function devices
  PCI: Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms

42 files changed:
Documentation/ABI/testing/sysfs-bus-pci
drivers/crypto/cavium/nitrox/nitrox_main.c
drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
drivers/pci/ats.c
drivers/pci/controller/dwc/pci-dra7xx.c
drivers/pci/controller/dwc/pci-keystone.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-uniphier.c
drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pci-ftpci100.c
drivers/pci/controller/pci-tegra.c
drivers/pci/controller/pci-xgene-msi.c
drivers/pci/controller/pcie-altera-msi.c
drivers/pci/controller/pcie-altera.c
drivers/pci/controller/pcie-brcmstb.c
drivers/pci/controller/pcie-iproc-msi.c
drivers/pci/controller/pcie-mediatek-gen3.c
drivers/pci/controller/pcie-mediatek.c
drivers/pci/controller/pcie-microchip-host.c
drivers/pci/controller/pcie-rcar-host.c
drivers/pci/controller/pcie-rockchip-host.c
drivers/pci/controller/pcie-xilinx-cpm.c
drivers/pci/controller/pcie-xilinx-nwl.c
drivers/pci/controller/pcie-xilinx.c
drivers/pci/hotplug/TODO
drivers/pci/hotplug/ibmphp_ebda.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pnv_php.c
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/syscall.c
include/linux/pci.h
include/linux/pci_hotplug.h

index 793cbb76cd2505d4365fddff9f485c609fc4a16d..d4ae03296861e4710e7befe7527937c5e165050b 100644 (file)
@@ -121,6 +121,23 @@ Description:
                child buses, and re-discover devices removed earlier
                from this part of the device tree.
 
+What:          /sys/bus/pci/devices/.../reset_method
+Date:          August 2021
+Contact:       Amey Narkhede <ameynarkhede03@gmail.com>
+Description:
+               Some devices allow an individual function to be reset
+               without affecting other functions in the same slot.
+
+               For devices that have this support, a file named
+               reset_method is present in sysfs.  Reading this file
+               gives names of the supported and enabled reset methods and
+               their ordering.  Writing a space-separated list of names of
+               reset methods sets the reset methods and ordering to be
+               used when resetting the device.  Writing an empty string
+               disables the ability to reset the device.  Writing
+               "default" enables all supported reset methods in the
+               default ordering.
+
 What:          /sys/bus/pci/devices/.../reset
 Date:          July 2009
 Contact:       Michael S. Tsirkin <mst@redhat.com>
index 96bc7b5c6532dede252ab285f5f553fec1719375..6c61817996a3338b5a193557f7ffd5cb06fd3bb6 100644 (file)
@@ -306,9 +306,7 @@ static int nitrox_device_flr(struct pci_dev *pdev)
                return -ENOMEM;
        }
 
-       /* check flr support */
-       if (pcie_has_flr(pdev))
-               pcie_flr(pdev);
+       pcie_reset_flr(pdev, PCI_RESET_DO_RESET);
 
        pci_restore_state(pdev);
 
index ffddb3126a3236d5bd99d6755400335adc167dbf..ac821c5532a4ed366eec9eae450cecfe67f17241 100644 (file)
@@ -526,7 +526,7 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                        oct->irq_name_storage = NULL;
                }
                /* Soft reset the octeon device before exiting */
-               if (oct->pci_dev->reset_fn)
+               if (!pcie_reset_flr(oct->pci_dev, PCI_RESET_PROBE))
                        octeon_pci_flr(oct);
                else
                        cn23xx_vf_ask_pf_to_do_flr(oct);
index 6d7d64939f823dd3842f31bf0c67510b82511dca..c967ad6e262678790583bb3137ff273ec31a16c3 100644 (file)
@@ -376,7 +376,7 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
        if (WARN_ON(pdev->pasid_enabled))
                return -EBUSY;
 
-       if (!pdev->eetlp_prefix_path)
+       if (!pdev->eetlp_prefix_path && !pdev->pasid_no_tlp)
                return -EINVAL;
 
        if (!pasid)
index 047cfbdc13303e3580cdef09c8113d6b8bc56583..fbbb78f6885e700ed4bddd8176f2b926b6cf9832 100644 (file)
@@ -204,7 +204,7 @@ static int dra7xx_pcie_handle_msi(struct pcie_port *pp, int index)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        unsigned long val;
-       int pos, irq;
+       int pos;
 
        val = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
                                   (index * MSI_REG_CTRL_BLOCK_SIZE));
@@ -213,9 +213,8 @@ static int dra7xx_pcie_handle_msi(struct pcie_port *pp, int index)
 
        pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL, 0);
        while (pos != MAX_MSI_IRQS_PER_CTRL) {
-               irq = irq_find_mapping(pp->irq_domain,
-                                      (index * MAX_MSI_IRQS_PER_CTRL) + pos);
-               generic_handle_irq(irq);
+               generic_handle_domain_irq(pp->irq_domain,
+                                         (index * MAX_MSI_IRQS_PER_CTRL) + pos);
                pos++;
                pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL, pos);
        }
@@ -257,7 +256,7 @@ static void dra7xx_pcie_msi_irq_handler(struct irq_desc *desc)
        struct dw_pcie *pci;
        struct pcie_port *pp;
        unsigned long reg;
-       u32 virq, bit;
+       u32 bit;
 
        chained_irq_enter(chip, desc);
 
@@ -276,11 +275,8 @@ static void dra7xx_pcie_msi_irq_handler(struct irq_desc *desc)
        case INTB:
        case INTC:
        case INTD:
-               for_each_set_bit(bit, &reg, PCI_NUM_INTX) {
-                       virq = irq_find_mapping(dra7xx->irq_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-               }
+               for_each_set_bit(bit, &reg, PCI_NUM_INTX)
+                       generic_handle_domain_irq(dra7xx->irq_domain, bit);
                break;
        }
 
index bde3b2824e89a6d021e03be075e904e1efe13f1e..865258d8c53c1bde47b39b5f6190e933a410ea04 100644 (file)
@@ -259,14 +259,12 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
        struct dw_pcie *pci = ks_pcie->pci;
        struct device *dev = pci->dev;
        u32 pending;
-       int virq;
 
        pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset));
 
        if (BIT(0) & pending) {
-               virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
-               dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
-               generic_handle_irq(virq);
+               dev_dbg(dev, ": irq: irq_offset %d", offset);
+               generic_handle_domain_irq(ks_pcie->legacy_irq_domain, offset);
        }
 
        /* EOI the INTx interrupt */
@@ -579,7 +577,7 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
        struct pcie_port *pp = &pci->pp;
        struct device *dev = pci->dev;
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       u32 vector, virq, reg, pos;
+       u32 vector, reg, pos;
 
        dev_dbg(dev, "%s, irq %d\n", __func__, irq);
 
@@ -600,10 +598,8 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
                        continue;
 
                vector = offset + (pos << 3);
-               virq = irq_linear_revmap(pp->irq_domain, vector);
-               dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector,
-                       virq);
-               generic_handle_irq(virq);
+               dev_dbg(dev, "irq: bit %d, vector %d\n", pos, vector);
+               generic_handle_domain_irq(pp->irq_domain, vector);
        }
 
        chained_irq_exit(chip, desc);
index a608ae1fad5761dc7cc64881c45a03d5e56a19db..d1d9b8344ec9cf7d8215992b8bcd10b2003f745a 100644 (file)
@@ -55,7 +55,7 @@ static struct msi_domain_info dw_pcie_msi_domain_info = {
 /* MSI int handler */
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 {
-       int i, pos, irq;
+       int i, pos;
        unsigned long val;
        u32 status, num_ctrls;
        irqreturn_t ret = IRQ_NONE;
@@ -74,10 +74,9 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
                pos = 0;
                while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL,
                                            pos)) != MAX_MSI_IRQS_PER_CTRL) {
-                       irq = irq_find_mapping(pp->irq_domain,
-                                              (i * MAX_MSI_IRQS_PER_CTRL) +
-                                              pos);
-                       generic_handle_irq(irq);
+                       generic_handle_domain_irq(pp->irq_domain,
+                                                 (i * MAX_MSI_IRQS_PER_CTRL) +
+                                                 pos);
                        pos++;
                }
        }
index 7e8bad32677014cc011313e895c6e09d197dc668..d842fd0181299bbc0f759963fc9b82d845425bee 100644 (file)
@@ -235,7 +235,7 @@ static void uniphier_pcie_irq_handler(struct irq_desc *desc)
        struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned long reg;
-       u32 val, bit, virq;
+       u32 val, bit;
 
        /* INT for debug */
        val = readl(priv->base + PCL_RCV_INT);
@@ -257,10 +257,8 @@ static void uniphier_pcie_irq_handler(struct irq_desc *desc)
        val = readl(priv->base + PCL_RCV_INTX);
        reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val);
 
-       for_each_set_bit(bit, &reg, PCI_NUM_INTX) {
-               virq = irq_linear_revmap(priv->legacy_irq_domain, bit);
-               generic_handle_irq(virq);
-       }
+       for_each_set_bit(bit, &reg, PCI_NUM_INTX)
+               generic_handle_domain_irq(priv->legacy_irq_domain, bit);
 
        chained_irq_exit(chip, desc);
 }
index c637de3a389bc807e51ff1ed0996de447a7e62c4..f3547aa60140c4fa61237858490852cf0b1167af 100644 (file)
@@ -92,7 +92,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
        u32 msi_data, msi_addr_lo, msi_addr_hi;
        u32 intr_status, msi_status;
        unsigned long shifted_status;
-       u32 bit, virq, val, mask;
+       u32 bit, val, mask;
 
        /*
         * The core provides a single interrupt for both INTx/MSI messages.
@@ -114,11 +114,10 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
                shifted_status >>= PAB_INTX_START;
                do {
                        for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
-                               virq = irq_find_mapping(rp->intx_domain,
-                                                       bit + 1);
-                               if (virq)
-                                       generic_handle_irq(virq);
-                               else
+                               int ret;
+                               ret = generic_handle_domain_irq(rp->intx_domain,
+                                                               bit + 1);
+                               if (ret)
                                        dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
                                                            bit);
 
@@ -155,9 +154,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
                dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
                        msi_data, msi_addr_hi, msi_addr_lo);
 
-               virq = irq_find_mapping(msi->dev_domain, msi_data);
-               if (virq)
-                       generic_handle_irq(virq);
+               generic_handle_domain_irq(msi->dev_domain, msi_data);
 
                msi_status = readl_relaxed(pcie->apb_csr_base +
                                           MSI_STATUS_OFFSET);
index c95ebe808f92b648298d404036e2652f41f4cfc7..d3515e207e121039b2839d6906d2c86565f01d87 100644 (file)
@@ -1049,7 +1049,7 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
 {
        u32 isr0_val, isr0_mask, isr0_status;
        u32 isr1_val, isr1_mask, isr1_status;
-       int i, virq;
+       int i;
 
        isr0_val = advk_readl(pcie, PCIE_ISR0_REG);
        isr0_mask = advk_readl(pcie, PCIE_ISR0_MASK_REG);
@@ -1077,8 +1077,7 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
                advk_writel(pcie, PCIE_ISR1_INTX_ASSERT(i),
                            PCIE_ISR1_REG);
 
-               virq = irq_find_mapping(pcie->irq_domain, i);
-               generic_handle_irq(virq);
+               generic_handle_domain_irq(pcie->irq_domain, i);
        }
 }
 
index aefef1986201acae7c09d69f8bf47aee3b7be160..88980a44461df681e2284007c165fbdee2bfe83a 100644 (file)
@@ -314,7 +314,7 @@ static void faraday_pci_irq_handler(struct irq_desc *desc)
        for (i = 0; i < 4; i++) {
                if ((irq_stat & BIT(i)) == 0)
                        continue;
-               generic_handle_irq(irq_find_mapping(p->irqdomain, i));
+               generic_handle_domain_irq(p->irqdomain, i);
        }
 
        chained_irq_exit(irqchip, desc);
index c979229a6d0df341b87ec113e675e2b01f2687f9..36f898643a4c4d8a5ff9a86d5d2a8e64c5f94069 100644 (file)
@@ -1553,12 +1553,10 @@ static void tegra_pcie_msi_irq(struct irq_desc *desc)
                while (reg) {
                        unsigned int offset = find_first_bit(&reg, 32);
                        unsigned int index = i * 32 + offset;
-                       unsigned int irq;
+                       int ret;
 
-                       irq = irq_find_mapping(msi->domain->parent, index);
-                       if (irq) {
-                               generic_handle_irq(irq);
-                       } else {
+                       ret = generic_handle_domain_irq(msi->domain->parent, index);
+                       if (ret) {
                                /*
                                 * that's weird who triggered this?
                                 * just clear it
index 1c34c897a7e2a7dddd5bf583aaca03cfc159a766..f1624bbb9f83308fbafa0d0797be63626f4c0f81 100644 (file)
@@ -291,8 +291,7 @@ static void xgene_msi_isr(struct irq_desc *desc)
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct xgene_msi_group *msi_groups;
        struct xgene_msi *xgene_msi;
-       unsigned int virq;
-       int msir_index, msir_val, hw_irq;
+       int msir_index, msir_val, hw_irq, ret;
        u32 intr_index, grp_select, msi_grp;
 
        chained_irq_enter(chip, desc);
@@ -330,10 +329,8 @@ static void xgene_msi_isr(struct irq_desc *desc)
                         * CPU0
                         */
                        hw_irq = hwirq_to_canonical_hwirq(hw_irq);
-                       virq = irq_find_mapping(xgene_msi->inner_domain, hw_irq);
-                       WARN_ON(!virq);
-                       if (virq != 0)
-                               generic_handle_irq(virq);
+                       ret = generic_handle_domain_irq(xgene_msi->inner_domain, hw_irq);
+                       WARN_ON_ONCE(ret);
                        msir_val &= ~(1 << intr_index);
                }
                grp_select &= ~(1 << msir_index);
index 98aa1dccc6e6858bec085f65b1c02b64c162e68e..7b1d3ebc34ecd72ee0f7c914e1a71afd432c43d6 100644 (file)
@@ -55,7 +55,7 @@ static void altera_msi_isr(struct irq_desc *desc)
        struct altera_msi *msi;
        unsigned long status;
        u32 bit;
-       u32 virq;
+       int ret;
 
        chained_irq_enter(chip, desc);
        msi = irq_desc_get_handler_data(desc);
@@ -65,11 +65,9 @@ static void altera_msi_isr(struct irq_desc *desc)
                        /* Dummy read from vector to clear the interrupt */
                        readl_relaxed(msi->vector_base + (bit * sizeof(u32)));
 
-                       virq = irq_find_mapping(msi->inner_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-                       else
-                               dev_err(&msi->pdev->dev, "unexpected MSI\n");
+                       ret = generic_handle_domain_irq(msi->inner_domain, bit);
+                       if (ret)
+                               dev_err_ratelimited(&msi->pdev->dev, "unexpected MSI\n");
                }
        }
 
index 523bd928b380a4d2245582f48825e9731859f339..2513e9363236805629aacfe54230da944dba8ffb 100644 (file)
@@ -646,7 +646,7 @@ static void altera_pcie_isr(struct irq_desc *desc)
        struct device *dev;
        unsigned long status;
        u32 bit;
-       u32 virq;
+       int ret;
 
        chained_irq_enter(chip, desc);
        pcie = irq_desc_get_handler_data(desc);
@@ -658,11 +658,9 @@ static void altera_pcie_isr(struct irq_desc *desc)
                        /* clear interrupts */
                        cra_writel(pcie, 1 << bit, P2A_INT_STATUS);
 
-                       virq = irq_find_mapping(pcie->irq_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-                       else
-                               dev_err(dev, "unexpected IRQ, INT%d\n", bit);
+                       ret = generic_handle_domain_irq(pcie->irq_domain, bit);
+                       if (ret)
+                               dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n", bit);
                }
        }
 
index 08bc788d9422c62e405dbcc1c7e09d710ee54388..cc30215f5a433697700ffbe24a5c6ab3f341a8c1 100644 (file)
@@ -476,7 +476,7 @@ static struct msi_domain_info brcm_msi_domain_info = {
 static void brcm_pcie_msi_isr(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned long status, virq;
+       unsigned long status;
        struct brcm_msi *msi;
        struct device *dev;
        u32 bit;
@@ -489,10 +489,9 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc)
        status >>= msi->legacy_shift;
 
        for_each_set_bit(bit, &status, msi->nr) {
-               virq = irq_find_mapping(msi->inner_domain, bit);
-               if (virq)
-                       generic_handle_irq(virq);
-               else
+               int ret;
+               ret = generic_handle_domain_irq(msi->inner_domain, bit);
+               if (ret)
                        dev_dbg(dev, "unexpected MSI\n");
        }
 
index 35a82124a12607163b7a2c9a8b3cfaa9010146dc..757b7fbcdc5910deaa9b8c5ba465d7f52106f47d 100644 (file)
@@ -326,7 +326,6 @@ static void iproc_msi_handler(struct irq_desc *desc)
        struct iproc_msi *msi;
        u32 eq, head, tail, nr_events;
        unsigned long hwirq;
-       int virq;
 
        chained_irq_enter(chip, desc);
 
@@ -362,8 +361,7 @@ static void iproc_msi_handler(struct irq_desc *desc)
                /* process all outstanding events */
                while (nr_events--) {
                        hwirq = decode_msi_hwirq(msi, eq, head);
-                       virq = irq_find_mapping(msi->inner_domain, hwirq);
-                       generic_handle_irq(virq);
+                       generic_handle_domain_irq(msi->inner_domain, hwirq);
 
                        head++;
                        head %= EQ_LEN;
index f3aeb8d4eaca8a25d366412da8f52a21478a08af..17c59b0d6978b663e2ff9a5cdac16e2a342ee9de 100644 (file)
@@ -645,7 +645,6 @@ static void mtk_pcie_msi_handler(struct mtk_pcie_port *port, int set_idx)
 {
        struct mtk_msi_set *msi_set = &port->msi_sets[set_idx];
        unsigned long msi_enable, msi_status;
-       unsigned int virq;
        irq_hw_number_t bit, hwirq;
 
        msi_enable = readl_relaxed(msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
@@ -659,8 +658,7 @@ static void mtk_pcie_msi_handler(struct mtk_pcie_port *port, int set_idx)
 
                for_each_set_bit(bit, &msi_status, PCIE_MSI_IRQS_PER_SET) {
                        hwirq = bit + set_idx * PCIE_MSI_IRQS_PER_SET;
-                       virq = irq_find_mapping(port->msi_bottom_domain, hwirq);
-                       generic_handle_irq(virq);
+                       generic_handle_domain_irq(port->msi_bottom_domain, hwirq);
                }
        } while (true);
 }
@@ -670,18 +668,15 @@ static void mtk_pcie_irq_handler(struct irq_desc *desc)
        struct mtk_pcie_port *port = irq_desc_get_handler_data(desc);
        struct irq_chip *irqchip = irq_desc_get_chip(desc);
        unsigned long status;
-       unsigned int virq;
        irq_hw_number_t irq_bit = PCIE_INTX_SHIFT;
 
        chained_irq_enter(irqchip, desc);
 
        status = readl_relaxed(port->base + PCIE_INT_STATUS_REG);
        for_each_set_bit_from(irq_bit, &status, PCI_NUM_INTX +
-                             PCIE_INTX_SHIFT) {
-               virq = irq_find_mapping(port->intx_domain,
-                                       irq_bit - PCIE_INTX_SHIFT);
-               generic_handle_irq(virq);
-       }
+                             PCIE_INTX_SHIFT)
+               generic_handle_domain_irq(port->intx_domain,
+                                         irq_bit - PCIE_INTX_SHIFT);
 
        irq_bit = PCIE_MSI_SHIFT;
        for_each_set_bit_from(irq_bit, &status, PCIE_MSI_SET_NUM +
index 25bee693834f95e282526992c430e78bce8ae79e..4cb5ea8e10694c8565581729339bcce87be52722 100644 (file)
@@ -602,7 +602,6 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
        struct mtk_pcie_port *port = irq_desc_get_handler_data(desc);
        struct irq_chip *irqchip = irq_desc_get_chip(desc);
        unsigned long status;
-       u32 virq;
        u32 bit = INTX_SHIFT;
 
        chained_irq_enter(irqchip, desc);
@@ -612,9 +611,8 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
                for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) {
                        /* Clear the INTx */
                        writel(1 << bit, port->base + PCIE_INT_STATUS);
-                       virq = irq_find_mapping(port->irq_domain,
-                                               bit - INTX_SHIFT);
-                       generic_handle_irq(virq);
+                       generic_handle_domain_irq(port->irq_domain,
+                                                 bit - INTX_SHIFT);
                }
        }
 
@@ -623,10 +621,8 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
                        unsigned long imsi_status;
 
                        while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
-                               for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) {
-                                       virq = irq_find_mapping(port->inner_domain, bit);
-                                       generic_handle_irq(virq);
-                               }
+                               for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM)
+                                       generic_handle_domain_irq(port->inner_domain, bit);
                        }
                        /* Clear MSI interrupt status */
                        writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
index fdab8202ae5d119f5346e7d461fd50bfb7b07c62..329f930d17aa737daa9f7458536e958962c695f7 100644 (file)
@@ -412,16 +412,14 @@ static void mc_handle_msi(struct irq_desc *desc)
                port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
        unsigned long status;
        u32 bit;
-       u32 virq;
+       int ret;
 
        status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
        if (status & PM_MSI_INT_MSI_MASK) {
                status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
                for_each_set_bit(bit, &status, msi->num_vectors) {
-                       virq = irq_find_mapping(msi->dev_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-                       else
+                       ret = generic_handle_domain_irq(msi->dev_domain, bit);
+                       if (ret)
                                dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
                                                    bit);
                }
@@ -570,17 +568,15 @@ static void mc_handle_intx(struct irq_desc *desc)
                port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
        unsigned long status;
        u32 bit;
-       u32 virq;
+       int ret;
 
        status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
        if (status & PM_MSI_INT_INTX_MASK) {
                status &= PM_MSI_INT_INTX_MASK;
                status >>= PM_MSI_INT_INTX_SHIFT;
                for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-                       virq = irq_find_mapping(port->intx_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-                       else
+                       ret = generic_handle_domain_irq(port->intx_domain, bit);
+                       if (ret)
                                dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
                                                    bit);
                }
@@ -745,7 +741,7 @@ static void mc_handle_event(struct irq_desc *desc)
        events = get_events(port);
 
        for_each_set_bit(bit, &events, NUM_EVENTS)
-               generic_handle_irq(irq_find_mapping(port->event_domain, bit));
+               generic_handle_domain_irq(port->event_domain, bit);
 
        chained_irq_exit(chip, desc);
 }
index 765cf2b45e24e22fe2b082f92e23de53f09dd452..00a8267eda147373b17febf629de29f846489e04 100644 (file)
@@ -486,12 +486,10 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
 
        while (reg) {
                unsigned int index = find_first_bit(&reg, 32);
-               unsigned int msi_irq;
+               int ret;
 
-               msi_irq = irq_find_mapping(msi->domain->parent, index);
-               if (msi_irq) {
-                       generic_handle_irq(msi_irq);
-               } else {
+               ret = generic_handle_domain_irq(msi->domain->parent, index);
+               if (ret) {
                        /* Unknown MSI, just clear it */
                        dev_dbg(dev, "unexpected MSI\n");
                        rcar_pci_write_reg(pcie, BIT(index), PCIEMSIFR);
index 78d04ac29cd56b93b1e52453cf16adc05bc1399f..c52316d0bfd2a9c0f622798ec8ab1f9fb6a752f7 100644 (file)
@@ -517,7 +517,7 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
        struct device *dev = rockchip->dev;
        u32 reg;
        u32 hwirq;
-       u32 virq;
+       int ret;
 
        chained_irq_enter(chip, desc);
 
@@ -528,10 +528,8 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
                hwirq = ffs(reg) - 1;
                reg &= ~BIT(hwirq);
 
-               virq = irq_find_mapping(rockchip->irq_domain, hwirq);
-               if (virq)
-                       generic_handle_irq(virq);
-               else
+               ret = generic_handle_domain_irq(rockchip->irq_domain, hwirq);
+               if (ret)
                        dev_err(dev, "unexpected IRQ, INT%d\n", hwirq);
        }
 
index 67937facd90cdcde68060f21060d4e0acf49af30..95426df03200014ad531517fc03e6af291cecc8f 100644 (file)
@@ -222,7 +222,7 @@ static void xilinx_cpm_pcie_intx_flow(struct irq_desc *desc)
                        pcie_read(port, XILINX_CPM_PCIE_REG_IDRN));
 
        for_each_set_bit(i, &val, PCI_NUM_INTX)
-               generic_handle_irq(irq_find_mapping(port->intx_domain, i));
+               generic_handle_domain_irq(port->intx_domain, i);
 
        chained_irq_exit(chip, desc);
 }
@@ -282,7 +282,7 @@ static void xilinx_cpm_pcie_event_flow(struct irq_desc *desc)
        val =  pcie_read(port, XILINX_CPM_PCIE_REG_IDR);
        val &= pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
        for_each_set_bit(i, &val, 32)
-               generic_handle_irq(irq_find_mapping(port->cpm_domain, i));
+               generic_handle_domain_irq(port->cpm_domain, i);
        pcie_write(port, val, XILINX_CPM_PCIE_REG_IDR);
 
        /*
index 8689311c5ef66a75dd1b70ce769b769eea06e142..3d178d5b652b388977e132560931a2d4f0baa2e4 100644 (file)
@@ -318,18 +318,14 @@ static void nwl_pcie_leg_handler(struct irq_desc *desc)
        struct nwl_pcie *pcie;
        unsigned long status;
        u32 bit;
-       u32 virq;
 
        chained_irq_enter(chip, desc);
        pcie = irq_desc_get_handler_data(desc);
 
        while ((status = nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
                                MSGF_LEG_SR_MASKALL) != 0) {
-               for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-                       virq = irq_find_mapping(pcie->legacy_irq_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
-               }
+               for_each_set_bit(bit, &status, PCI_NUM_INTX)
+                       generic_handle_domain_irq(pcie->legacy_irq_domain, bit);
        }
 
        chained_irq_exit(chip, desc);
@@ -340,16 +336,13 @@ static void nwl_pcie_handle_msi_irq(struct nwl_pcie *pcie, u32 status_reg)
        struct nwl_msi *msi;
        unsigned long status;
        u32 bit;
-       u32 virq;
 
        msi = &pcie->msi;
 
        while ((status = nwl_bridge_readl(pcie, status_reg)) != 0) {
                for_each_set_bit(bit, &status, 32) {
                        nwl_bridge_writel(pcie, 1 << bit, status_reg);
-                       virq = irq_find_mapping(msi->dev_domain, bit);
-                       if (virq)
-                               generic_handle_irq(virq);
+                       generic_handle_domain_irq(msi->dev_domain, bit);
                }
        }
 }
index 14001febf59a0e2ef50e9e71a3a1803207553dab..aa9bdcebc83835bcea317852781182317118fd82 100644 (file)
@@ -385,7 +385,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
        }
 
        if (status & (XILINX_PCIE_INTR_INTX | XILINX_PCIE_INTR_MSI)) {
-               unsigned int irq;
+               struct irq_domain *domain;
 
                val = pcie_read(port, XILINX_PCIE_REG_RPIFR1);
 
@@ -399,19 +399,18 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
                if (val & XILINX_PCIE_RPIFR1_MSI_INTR) {
                        val = pcie_read(port, XILINX_PCIE_REG_RPIFR2) &
                                XILINX_PCIE_RPIFR2_MSG_DATA;
-                       irq = irq_find_mapping(port->msi_domain->parent, val);
+                       domain = port->msi_domain->parent;
                } else {
                        val = (val & XILINX_PCIE_RPIFR1_INTR_MASK) >>
                                XILINX_PCIE_RPIFR1_INTR_SHIFT;
-                       irq = irq_find_mapping(port->leg_domain, val);
+                       domain = port->leg_domain;
                }
 
                /* Clear interrupt FIFO register 1 */
                pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK,
                           XILINX_PCIE_REG_RPIFR1);
 
-               if (irq)
-                       generic_handle_irq(irq);
+               generic_handle_domain_irq(domain, val);
        }
 
        if (status & XILINX_PCIE_INTR_SLV_UNSUPP)
index a32070be5adf95921aa00b277b827ae881e8a2a1..cc6194aa24c1500922191a763524d6482c9491d3 100644 (file)
@@ -40,9 +40,6 @@ ibmphp:
 
 * The return value of pci_hp_register() is not checked.
 
-* iounmap(io_mem) is called in the error path of ebda_rsrc_controller()
-  and once more in the error path of its caller ibmphp_access_ebda().
-
 * The various slot data structures are difficult to follow and need to be
   simplified.  A lot of functions are too large and too complex, they need
   to be broken up into smaller, manageable pieces.  Negative examples are
index 11a2661dc06277319e0cd2ed873cd4b6408bdebc..7fb75401ad8a719ea7fd061cd075df579548b643 100644 (file)
@@ -714,8 +714,7 @@ static int __init ebda_rsrc_controller(void)
                /* init hpc structure */
                hpc_ptr = alloc_ebda_hpc(slot_num, bus_num);
                if (!hpc_ptr) {
-                       rc = -ENOMEM;
-                       goto error_no_hpc;
+                       return -ENOMEM;
                }
                hpc_ptr->ctlr_id = ctlr_id;
                hpc_ptr->ctlr_relative_id = ctlr;
@@ -910,8 +909,6 @@ error:
        kfree(tmp_slot);
 error_no_slot:
        free_ebda_hpc(hpc_ptr);
-error_no_hpc:
-       iounmap(io_mem);
        return rc;
 }
 
index d4a930881054de74ef0b53947e72dc13d3a7dc11..69fd401691be6e6a5ae4aa56f294ae591134039c 100644 (file)
@@ -184,7 +184,7 @@ void pciehp_release_ctrl(struct controller *ctrl);
 
 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot);
 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot);
-int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe);
+int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe);
 int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
 int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
 int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
index 9d06939736c0f0634670bf346df2138905854d71..3024d7e85e6a70d53856c5a6a468c3c3e6d50a6e 100644 (file)
@@ -870,7 +870,7 @@ void pcie_disable_interrupt(struct controller *ctrl)
  * momentarily, if we see that they could interfere. Also, clear any spurious
  * events after.
  */
-int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe)
+int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe)
 {
        struct controller *ctrl = to_ctrl(hotplug_slot);
        struct pci_dev *pdev = ctrl_dev(ctrl);
index 04565162a44954dbf97f5bd77b12c68f200586aa..f4c2e6e01be0498719ff2dbb14b4114d0e7a45d2 100644 (file)
@@ -526,7 +526,7 @@ scan:
        return 0;
 }
 
-static int pnv_php_reset_slot(struct hotplug_slot *slot, int probe)
+static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
 {
        struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
        struct pci_dev *bridge = php_slot->pdev;
index 36bc23e2175927e15d475e577a95ef4970849f75..fe286c861187bd919336140e6d0527b36789d54b 100644 (file)
@@ -934,58 +934,77 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
 
 static struct acpi_device *acpi_pci_find_companion(struct device *dev);
 
+void pci_set_acpi_fwnode(struct pci_dev *dev)
+{
+       if (!ACPI_COMPANION(&dev->dev) && !pci_dev_is_added(dev))
+               ACPI_COMPANION_SET(&dev->dev,
+                                  acpi_pci_find_companion(&dev->dev));
+}
+
+/**
+ * pci_dev_acpi_reset - do a function level reset using _RST method
+ * @dev: device to reset
+ * @probe: if true, return 0 if device supports _RST
+ */
+int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
+{
+       acpi_handle handle = ACPI_HANDLE(&dev->dev);
+
+       if (!handle || !acpi_has_method(handle, "_RST"))
+               return -ENOTTY;
+
+       if (probe)
+               return 0;
+
+       if (ACPI_FAILURE(acpi_evaluate_object(handle, "_RST", NULL, NULL))) {
+               pci_warn(dev, "ACPI _RST failed\n");
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+static bool acpi_pci_power_manageable(struct pci_dev *dev)
+{
+       struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+
+       if (!adev)
+               return false;
+       return acpi_device_power_manageable(adev);
+}
+
 static bool acpi_pci_bridge_d3(struct pci_dev *dev)
 {
-       const struct fwnode_handle *fwnode;
+       const union acpi_object *obj;
        struct acpi_device *adev;
-       struct pci_dev *root;
-       u8 val;
+       struct pci_dev *rpdev;
 
        if (!dev->is_hotplug_bridge)
                return false;
 
        /* Assume D3 support if the bridge is power-manageable by ACPI. */
-       adev = ACPI_COMPANION(&dev->dev);
-       if (!adev && !pci_dev_is_added(dev)) {
-               adev = acpi_pci_find_companion(&dev->dev);
-               ACPI_COMPANION_SET(&dev->dev, adev);
-       }
-
-       if (adev && acpi_device_power_manageable(adev))
+       if (acpi_pci_power_manageable(dev))
                return true;
 
        /*
-        * Look for a special _DSD property for the root port and if it
-        * is set we know the hierarchy behind it supports D3 just fine.
+        * The ACPI firmware will provide the device-specific properties through
+        * _DSD configuration object. Look for the 'HotPlugSupportInD3' property
+        * for the root port and if it is set we know the hierarchy behind it
+        * supports D3 just fine.
         */
-       root = pcie_find_root_port(dev);
-       if (!root)
+       rpdev = pcie_find_root_port(dev);
+       if (!rpdev)
                return false;
 
-       adev = ACPI_COMPANION(&root->dev);
-       if (root == dev) {
-               /*
-                * It is possible that the ACPI companion is not yet bound
-                * for the root port so look it up manually here.
-                */
-               if (!adev && !pci_dev_is_added(root))
-                       adev = acpi_pci_find_companion(&root->dev);
-       }
-
+       adev = ACPI_COMPANION(&rpdev->dev);
        if (!adev)
                return false;
 
-       fwnode = acpi_fwnode_handle(adev);
-       if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val))
+       if (acpi_dev_get_property(adev, "HotPlugSupportInD3",
+                                  ACPI_TYPE_INTEGER, &obj) < 0)
                return false;
 
-       return val == 1;
-}
-
-static bool acpi_pci_power_manageable(struct pci_dev *dev)
-{
-       struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
-       return adev ? acpi_device_power_manageable(adev) : false;
+       return obj->integer.value == 1;
 }
 
 static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
index 5d63df7c18206ae416f800fa5f35ea37cb0aab9b..2fd44c97b7ec09402f0685975adf9c1f28f955fc 100644 (file)
@@ -1367,7 +1367,7 @@ static umode_t pci_dev_reset_attr_is_visible(struct kobject *kobj,
 {
        struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
 
-       if (!pdev->reset_fn)
+       if (!pci_reset_supported(pdev))
                return 0;
 
        return a->mode;
@@ -1491,6 +1491,7 @@ const struct attribute_group *pci_dev_groups[] = {
        &pci_dev_config_attr_group,
        &pci_dev_rom_attr_group,
        &pci_dev_reset_attr_group,
+       &pci_dev_reset_method_attr_group,
        &pci_dev_vpd_attr_group,
 #ifdef CONFIG_DMI
        &pci_dev_smbios_attr_group,
index e0c6ceced2073f04d3eaf0dd625521a388db4494..c3f6ff3bd2af5bae1afd01019b1561b171cd970d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/vmalloc.h>
 #include <asm/dma.h>
 #include <linux/aer.h>
+#include <linux/bitfield.h>
 #include "pci.h"
 
 DEFINE_MUTEX(pci_slot_mutex);
@@ -72,6 +73,11 @@ static void pci_dev_d3_sleep(struct pci_dev *dev)
                msleep(delay);
 }
 
+bool pci_reset_supported(struct pci_dev *dev)
+{
+       return dev->reset_methods[0] != 0;
+}
+
 #ifdef CONFIG_PCI_DOMAINS
 int pci_domains_supported = 1;
 #endif
@@ -206,32 +212,36 @@ int pci_status_get_and_clear_errors(struct pci_dev *pdev)
 EXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors);
 
 #ifdef CONFIG_HAS_IOMEM
-void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+static void __iomem *__pci_ioremap_resource(struct pci_dev *pdev, int bar,
+                                           bool write_combine)
 {
        struct resource *res = &pdev->resource[bar];
+       resource_size_t start = res->start;
+       resource_size_t size = resource_size(res);
 
        /*
         * Make sure the BAR is actually a memory resource, not an IO resource
         */
        if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
-               pci_warn(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
+               pci_err(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
                return NULL;
        }
-       return ioremap(res->start, resource_size(res));
+
+       if (write_combine)
+               return ioremap_wc(start, size);
+
+       return ioremap(start, size);
+}
+
+void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+{
+       return __pci_ioremap_resource(pdev, bar, false);
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_bar);
 
 void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
 {
-       /*
-        * Make sure the BAR is actually a memory resource, not an IO resource
-        */
-       if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
-               WARN_ON(1);
-               return NULL;
-       }
-       return ioremap_wc(pci_resource_start(pdev, bar),
-                         pci_resource_len(pdev, bar));
+       return __pci_ioremap_resource(pdev, bar, true);
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
 #endif
@@ -4621,32 +4631,12 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(pci_wait_for_pending_transaction);
 
-/**
- * pcie_has_flr - check if a device supports function level resets
- * @dev: device to check
- *
- * Returns true if the device advertises support for PCIe function level
- * resets.
- */
-bool pcie_has_flr(struct pci_dev *dev)
-{
-       u32 cap;
-
-       if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
-               return false;
-
-       pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
-       return cap & PCI_EXP_DEVCAP_FLR;
-}
-EXPORT_SYMBOL_GPL(pcie_has_flr);
-
 /**
  * pcie_flr - initiate a PCIe function level reset
  * @dev: device to reset
  *
- * Initiate a function level reset on @dev.  The caller should ensure the
- * device supports FLR before calling this function, e.g. by using the
- * pcie_has_flr() helper.
+ * Initiate a function level reset unconditionally on @dev without
+ * checking any flags and DEVCAP
  */
 int pcie_flr(struct pci_dev *dev)
 {
@@ -4669,7 +4659,29 @@ int pcie_flr(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pcie_flr);
 
-static int pci_af_flr(struct pci_dev *dev, int probe)
+/**
+ * pcie_reset_flr - initiate a PCIe function level reset
+ * @dev: device to reset
+ * @probe: if true, return 0 if device can be reset this way
+ *
+ * Initiate a function level reset on @dev.
+ */
+int pcie_reset_flr(struct pci_dev *dev, bool probe)
+{
+       if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
+               return -ENOTTY;
+
+       if (!(dev->devcap & PCI_EXP_DEVCAP_FLR))
+               return -ENOTTY;
+
+       if (probe)
+               return 0;
+
+       return pcie_flr(dev);
+}
+EXPORT_SYMBOL_GPL(pcie_reset_flr);
+
+static int pci_af_flr(struct pci_dev *dev, bool probe)
 {
        int pos;
        u8 cap;
@@ -4716,7 +4728,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
 /**
  * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
  * @dev: Device to reset.
- * @probe: If set, only check if the device can be reset this way.
+ * @probe: if true, return 0 if the device can be reset this way.
  *
  * If @dev supports native PCI PM and its PCI_PM_CTRL_NO_SOFT_RESET flag is
  * unset, it will be reinitialized internally when going from PCI_D3hot to
@@ -4728,7 +4740,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
  * by default (i.e. unless the @dev's d3hot_delay field has a different value).
  * Moreover, only devices in D0 can be reset by this function.
  */
-static int pci_pm_reset(struct pci_dev *dev, int probe)
+static int pci_pm_reset(struct pci_dev *dev, bool probe)
 {
        u16 csr;
 
@@ -4988,7 +5000,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_bridge_secondary_bus_reset);
 
-static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+static int pci_parent_bus_reset(struct pci_dev *dev, bool probe)
 {
        struct pci_dev *pdev;
 
@@ -5006,7 +5018,7 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
        return pci_bridge_secondary_bus_reset(dev->bus->self);
 }
 
-static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
+static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, bool probe)
 {
        int rc = -ENOTTY;
 
@@ -5021,7 +5033,7 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
        return rc;
 }
 
-static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
+static int pci_dev_reset_slot_function(struct pci_dev *dev, bool probe)
 {
        if (dev->multifunction || dev->subordinate || !dev->slot ||
            dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
@@ -5030,7 +5042,7 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
        return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
 }
 
-static int pci_reset_bus_function(struct pci_dev *dev, int probe)
+static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
 {
        int rc;
 
@@ -5114,6 +5126,139 @@ static void pci_dev_restore(struct pci_dev *dev)
                err_handler->reset_done(dev);
 }
 
+/* dev->reset_methods[] is a 0-terminated list of indices into this array */
+static const struct pci_reset_fn_method pci_reset_fn_methods[] = {
+       { },
+       { pci_dev_specific_reset, .name = "device_specific" },
+       { pci_dev_acpi_reset, .name = "acpi" },
+       { pcie_reset_flr, .name = "flr" },
+       { pci_af_flr, .name = "af_flr" },
+       { pci_pm_reset, .name = "pm" },
+       { pci_reset_bus_function, .name = "bus" },
+};
+
+static ssize_t reset_method_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       ssize_t len = 0;
+       int i, m;
+
+       for (i = 0; i < PCI_NUM_RESET_METHODS; i++) {
+               m = pdev->reset_methods[i];
+               if (!m)
+                       break;
+
+               len += sysfs_emit_at(buf, len, "%s%s", len ? " " : "",
+                                    pci_reset_fn_methods[m].name);
+       }
+
+       if (len)
+               len += sysfs_emit_at(buf, len, "\n");
+
+       return len;
+}
+
+static int reset_method_lookup(const char *name)
+{
+       int m;
+
+       for (m = 1; m < PCI_NUM_RESET_METHODS; m++) {
+               if (sysfs_streq(name, pci_reset_fn_methods[m].name))
+                       return m;
+       }
+
+       return 0;       /* not found */
+}
+
+static ssize_t reset_method_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       char *options, *name;
+       int m, n;
+       u8 reset_methods[PCI_NUM_RESET_METHODS] = { 0 };
+
+       if (sysfs_streq(buf, "")) {
+               pdev->reset_methods[0] = 0;
+               pci_warn(pdev, "All device reset methods disabled by user");
+               return count;
+       }
+
+       if (sysfs_streq(buf, "default")) {
+               pci_init_reset_methods(pdev);
+               return count;
+       }
+
+       options = kstrndup(buf, count, GFP_KERNEL);
+       if (!options)
+               return -ENOMEM;
+
+       n = 0;
+       while ((name = strsep(&options, " ")) != NULL) {
+               if (sysfs_streq(name, ""))
+                       continue;
+
+               name = strim(name);
+
+               m = reset_method_lookup(name);
+               if (!m) {
+                       pci_err(pdev, "Invalid reset method '%s'", name);
+                       goto error;
+               }
+
+               if (pci_reset_fn_methods[m].reset_fn(pdev, PCI_RESET_PROBE)) {
+                       pci_err(pdev, "Unsupported reset method '%s'", name);
+                       goto error;
+               }
+
+               if (n == PCI_NUM_RESET_METHODS - 1) {
+                       pci_err(pdev, "Too many reset methods\n");
+                       goto error;
+               }
+
+               reset_methods[n++] = m;
+       }
+
+       reset_methods[n] = 0;
+
+       /* Warn if dev-specific supported but not highest priority */
+       if (pci_reset_fn_methods[1].reset_fn(pdev, PCI_RESET_PROBE) == 0 &&
+           reset_methods[0] != 1)
+               pci_warn(pdev, "Device-specific reset disabled/de-prioritized by user");
+       memcpy(pdev->reset_methods, reset_methods, sizeof(pdev->reset_methods));
+       kfree(options);
+       return count;
+
+error:
+       /* Leave previous methods unchanged */
+       kfree(options);
+       return -EINVAL;
+}
+static DEVICE_ATTR_RW(reset_method);
+
+static struct attribute *pci_dev_reset_method_attrs[] = {
+       &dev_attr_reset_method.attr,
+       NULL,
+};
+
+static umode_t pci_dev_reset_method_attr_is_visible(struct kobject *kobj,
+                                                   struct attribute *a, int n)
+{
+       struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+
+       if (!pci_reset_supported(pdev))
+               return 0;
+
+       return a->mode;
+}
+
+const struct attribute_group pci_dev_reset_method_attr_group = {
+       .attrs = pci_dev_reset_method_attrs,
+       .is_visible = pci_dev_reset_method_attr_is_visible,
+};
+
 /**
  * __pci_reset_function_locked - reset a PCI device function while holding
  * the @dev mutex lock.
@@ -5136,66 +5281,64 @@ static void pci_dev_restore(struct pci_dev *dev)
  */
 int __pci_reset_function_locked(struct pci_dev *dev)
 {
-       int rc;
+       int i, m, rc = -ENOTTY;
 
        might_sleep();
 
        /*
-        * A reset method returns -ENOTTY if it doesn't support this device
-        * and we should try the next method.
+        * A reset method returns -ENOTTY if it doesn't support this device and
+        * we should try the next method.
         *
-        * If it returns 0 (success), we're finished.  If it returns any
-        * other error, we're also finished: this indicates that further
-        * reset mechanisms might be broken on the device.
+        * If it returns 0 (success), we're finished.  If it returns any other
+        * error, we're also finished: this indicates that further reset
+        * mechanisms might be broken on the device.
         */
-       rc = pci_dev_specific_reset(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       if (pcie_has_flr(dev)) {
-               rc = pcie_flr(dev);
+       for (i = 0; i < PCI_NUM_RESET_METHODS; i++) {
+               m = dev->reset_methods[i];
+               if (!m)
+                       return -ENOTTY;
+
+               rc = pci_reset_fn_methods[m].reset_fn(dev, PCI_RESET_DO_RESET);
+               if (!rc)
+                       return 0;
                if (rc != -ENOTTY)
                        return rc;
        }
-       rc = pci_af_flr(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       rc = pci_pm_reset(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       return pci_reset_bus_function(dev, 0);
+
+       return -ENOTTY;
 }
 EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
 
 /**
- * pci_probe_reset_function - check whether the device can be safely reset
- * @dev: PCI device to reset
+ * pci_init_reset_methods - check whether device can be safely reset
+ * and store supported reset mechanisms.
+ * @dev: PCI device to check for reset mechanisms
  *
  * Some devices allow an individual function to be reset without affecting
- * other functions in the same device.  The PCI device must be responsive
- * to PCI config space in order to use this function.
+ * other functions in the same device.  The PCI device must be in D0-D3hot
+ * state.
  *
- * Returns 0 if the device function can be reset or negative if the
- * device doesn't support resetting a single function.
+ * Stores reset mechanisms supported by device in reset_methods byte array
+ * which is a member of struct pci_dev.
  */
-int pci_probe_reset_function(struct pci_dev *dev)
+void pci_init_reset_methods(struct pci_dev *dev)
 {
-       int rc;
+       int m, i, rc;
+
+       BUILD_BUG_ON(ARRAY_SIZE(pci_reset_fn_methods) != PCI_NUM_RESET_METHODS);
 
        might_sleep();
 
-       rc = pci_dev_specific_reset(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
-       if (pcie_has_flr(dev))
-               return 0;
-       rc = pci_af_flr(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
-       rc = pci_pm_reset(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
+       i = 0;
+       for (m = 1; m < PCI_NUM_RESET_METHODS; m++) {
+               rc = pci_reset_fn_methods[m].reset_fn(dev, PCI_RESET_PROBE);
+               if (!rc)
+                       dev->reset_methods[i++] = m;
+               else if (rc != -ENOTTY)
+                       break;
+       }
 
-       return pci_reset_bus_function(dev, 1);
+       dev->reset_methods[i] = 0;
 }
 
 /**
@@ -5218,7 +5361,7 @@ int pci_reset_function(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        pci_dev_lock(dev);
@@ -5254,7 +5397,7 @@ int pci_reset_function_locked(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        pci_dev_save_and_disable(dev);
@@ -5277,7 +5420,7 @@ int pci_try_reset_function(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        if (!pci_dev_trylock(dev))
@@ -5505,7 +5648,7 @@ static void pci_slot_restore_locked(struct pci_slot *slot)
        }
 }
 
-static int pci_slot_reset(struct pci_slot *slot, int probe)
+static int pci_slot_reset(struct pci_slot *slot, bool probe)
 {
        int rc;
 
@@ -5533,7 +5676,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
  */
 int pci_probe_reset_slot(struct pci_slot *slot)
 {
-       return pci_slot_reset(slot, 1);
+       return pci_slot_reset(slot, PCI_RESET_PROBE);
 }
 EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
 
@@ -5556,14 +5699,14 @@ static int __pci_reset_slot(struct pci_slot *slot)
 {
        int rc;
 
-       rc = pci_slot_reset(slot, 1);
+       rc = pci_slot_reset(slot, PCI_RESET_PROBE);
        if (rc)
                return rc;
 
        if (pci_slot_trylock(slot)) {
                pci_slot_save_and_disable_locked(slot);
                might_sleep();
-               rc = pci_reset_hotplug_slot(slot->hotplug, 0);
+               rc = pci_reset_hotplug_slot(slot->hotplug, PCI_RESET_DO_RESET);
                pci_slot_restore_locked(slot);
                pci_slot_unlock(slot);
        } else
@@ -5572,7 +5715,7 @@ static int __pci_reset_slot(struct pci_slot *slot)
        return rc;
 }
 
-static int pci_bus_reset(struct pci_bus *bus, int probe)
+static int pci_bus_reset(struct pci_bus *bus, bool probe)
 {
        int ret;
 
@@ -5618,14 +5761,14 @@ int pci_bus_error_reset(struct pci_dev *bridge)
                        goto bus_reset;
 
        list_for_each_entry(slot, &bus->slots, list)
-               if (pci_slot_reset(slot, 0))
+               if (pci_slot_reset(slot, PCI_RESET_DO_RESET))
                        goto bus_reset;
 
        mutex_unlock(&pci_slot_mutex);
        return 0;
 bus_reset:
        mutex_unlock(&pci_slot_mutex);
-       return pci_bus_reset(bridge->subordinate, 0);
+       return pci_bus_reset(bridge->subordinate, PCI_RESET_DO_RESET);
 }
 
 /**
@@ -5636,7 +5779,7 @@ bus_reset:
  */
 int pci_probe_reset_bus(struct pci_bus *bus)
 {
-       return pci_bus_reset(bus, 1);
+       return pci_bus_reset(bus, PCI_RESET_PROBE);
 }
 EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
 
@@ -5650,7 +5793,7 @@ static int __pci_reset_bus(struct pci_bus *bus)
 {
        int rc;
 
-       rc = pci_bus_reset(bus, 1);
+       rc = pci_bus_reset(bus, PCI_RESET_PROBE);
        if (rc)
                return rc;
 
index 93dcdd4310726fbf7e797c18f622c72e8ba51a46..05b7e7e04246741e00a4580591c1f1a6afce1991 100644 (file)
@@ -33,7 +33,8 @@ enum pci_mmap_api {
 int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
                  enum pci_mmap_api mmap_api);
 
-int pci_probe_reset_function(struct pci_dev *dev);
+bool pci_reset_supported(struct pci_dev *dev);
+void pci_init_reset_methods(struct pci_dev *dev);
 int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
 int pci_bus_error_reset(struct pci_dev *dev);
 
@@ -607,13 +608,18 @@ static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
 struct pci_dev_reset_methods {
        u16 vendor;
        u16 device;
-       int (*reset)(struct pci_dev *dev, int probe);
+       int (*reset)(struct pci_dev *dev, bool probe);
+};
+
+struct pci_reset_fn_method {
+       int (*reset_fn)(struct pci_dev *pdev, bool probe);
+       char *name;
 };
 
 #ifdef CONFIG_PCI_QUIRKS
-int pci_dev_specific_reset(struct pci_dev *dev, int probe);
+int pci_dev_specific_reset(struct pci_dev *dev, bool probe);
 #else
-static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
+static inline int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
 {
        return -ENOTTY;
 }
@@ -701,7 +707,15 @@ static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL
 #ifdef CONFIG_ACPI
 int pci_acpi_program_hp_params(struct pci_dev *dev);
 extern const struct attribute_group pci_dev_acpi_attr_group;
+void pci_set_acpi_fwnode(struct pci_dev *dev);
+int pci_dev_acpi_reset(struct pci_dev *dev, bool probe);
 #else
+static inline int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
+{
+       return -ENOTTY;
+}
+
+static inline void pci_set_acpi_fwnode(struct pci_dev *dev) {}
 static inline int pci_acpi_program_hp_params(struct pci_dev *dev)
 {
        return -ENODEV;
@@ -712,4 +726,6 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev)
 extern const struct attribute_group aspm_ctrl_attr_group;
 #endif
 
+extern const struct attribute_group pci_dev_reset_method_attr_group;
+
 #endif /* DRIVERS_PCI_H */
index df4ba9b384c24abf4961a9421d4571dce6ef6ccb..9784fdcf30061c7ffd407b73bf20f60a8c70ca62 100644 (file)
@@ -1407,13 +1407,11 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
        }
 
        if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {
-               if (pcie_has_flr(dev)) {
-                       rc = pcie_flr(dev);
-                       pci_info(dev, "has been reset (%d)\n", rc);
-               } else {
-                       pci_info(dev, "not reset (no FLR support)\n");
-                       rc = -ENOTTY;
-               }
+               rc = pcie_reset_flr(dev, PCI_RESET_DO_RESET);
+               if (!rc)
+                       pci_info(dev, "has been reset\n");
+               else
+                       pci_info(dev, "not reset (no FLR support: %d)\n", rc);
        } else {
                rc = pci_bus_error_reset(dev);
                pci_info(dev, "%s Port link has been reset (%d)\n",
index e1fed6649c41f73509b4bba28b8034988f675433..3ee63968deaa5880dc700feb3d17b338a8557e68 100644 (file)
@@ -257,8 +257,13 @@ static int get_port_device_capability(struct pci_dev *dev)
                services |= PCIE_PORT_SERVICE_DPC;
 
        if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
-           pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
-               services |= PCIE_PORT_SERVICE_BWNOTIF;
+           pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
+               u32 linkcap;
+
+               pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &linkcap);
+               if (linkcap & PCI_EXP_LNKCAP_LBNC)
+                       services |= PCIE_PORT_SERVICE_BWNOTIF;
+       }
 
        return services;
 }
index 79177ac37880fb14a61617c77a7ad8245d8c32ec..081b3339fb3d9a753831cd2c95b485d431c9f172 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/hypervisor.h>
 #include <linux/irqdomain.h>
 #include <linux/pm_runtime.h>
+#include <linux/bitfield.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -1498,8 +1499,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
        pdev->pcie_cap = pos;
        pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
        pdev->pcie_flags_reg = reg16;
-       pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
-       pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
+       pci_read_config_dword(pdev, pos + PCI_EXP_DEVCAP, &pdev->devcap);
+       pdev->pcie_mpss = FIELD_GET(PCI_EXP_DEVCAP_PAYLOAD, pdev->devcap);
 
        parent = pci_upstream_bridge(pdev);
        if (!parent)
@@ -1809,6 +1810,9 @@ int pci_setup_device(struct pci_dev *dev)
        dev->error_state = pci_channel_io_normal;
        set_pcie_port_type(dev);
 
+       pci_set_of_node(dev);
+       pci_set_acpi_fwnode(dev);
+
        pci_dev_assign_slot(dev);
 
        /*
@@ -1946,6 +1950,7 @@ int pci_setup_device(struct pci_dev *dev)
        default:                                    /* unknown header */
                pci_err(dev, "unknown header type %02x, ignoring device\n",
                        dev->hdr_type);
+               pci_release_of_node(dev);
                return -EIO;
 
        bad:
@@ -2374,10 +2379,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
 
-       pci_set_of_node(dev);
-
        if (pci_setup_device(dev)) {
-               pci_release_of_node(dev);
                pci_bus_put(dev->bus);
                kfree(dev);
                return NULL;
@@ -2428,9 +2430,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
        pci_rcec_init(dev);             /* Root Complex Event Collector */
 
        pcie_report_downtraining(dev);
-
-       if (pci_probe_reset_function(dev) == 0)
-               dev->reset_fn = 1;
+       pci_init_reset_methods(dev);
 }
 
 /*
index 68e47002b72cee47e489e3c6eda4d91266f51bda..d7542e01fb56720720995065cb0a209bed0dc819 100644 (file)
@@ -1821,6 +1821,45 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,     PCI_DEVICE_ID_INTEL_E7525_MCH,  quir
 
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_HUAWEI, 0x1610, PCI_CLASS_BRIDGE_PCI, 8, quirk_pcie_mch);
 
+/*
+ * HiSilicon KunPeng920 and KunPeng930 have devices appear as PCI but are
+ * actually on the AMBA bus. These fake PCI devices can support SVA via
+ * SMMU stall feature, by setting dma-can-stall for ACPI platforms.
+ *
+ * Normally stalling must not be enabled for PCI devices, since it would
+ * break the PCI requirement for free-flowing writes and may lead to
+ * deadlock.  We expect PCI devices to support ATS and PRI if they want to
+ * be fault-tolerant, so there's no ACPI binding to describe anything else,
+ * even when a "PCI" device turns out to be a regular old SoC device
+ * dressed up as a RCiEP and normal rules don't apply.
+ */
+static void quirk_huawei_pcie_sva(struct pci_dev *pdev)
+{
+       struct property_entry properties[] = {
+               PROPERTY_ENTRY_BOOL("dma-can-stall"),
+               {},
+       };
+
+       if (pdev->revision != 0x21 && pdev->revision != 0x30)
+               return;
+
+       pdev->pasid_no_tlp = 1;
+
+       /*
+        * Set the dma-can-stall property on ACPI platforms. Device tree
+        * can set it directly.
+        */
+       if (!pdev->dev.of_node &&
+           device_add_properties(&pdev->dev, properties))
+               pci_warn(pdev, "could not add stall property");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa250, quirk_huawei_pcie_sva);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa251, quirk_huawei_pcie_sva);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa255, quirk_huawei_pcie_sva);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa256, quirk_huawei_pcie_sva);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa258, quirk_huawei_pcie_sva);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa259, quirk_huawei_pcie_sva);
+
 /*
  * It's possible for the MSI to get corrupted if SHPC and ACPI are used
  * together on certain PXH-based systems.
@@ -3234,12 +3273,13 @@ static void fixup_mpss_256(struct pci_dev *dev)
 {
        dev->pcie_mpss = 1; /* 256 bytes */
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOLARFLARE,
-                        PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0, fixup_mpss_256);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOLARFLARE,
-                        PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1, fixup_mpss_256);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOLARFLARE,
-                        PCI_DEVICE_ID_SOLARFLARE_SFC4000B, fixup_mpss_256);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLARFLARE,
+                       PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0, fixup_mpss_256);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLARFLARE,
+                       PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1, fixup_mpss_256);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLARFLARE,
+                       PCI_DEVICE_ID_SOLARFLARE_SFC4000B, fixup_mpss_256);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ASMEDIA, 0x0612, fixup_mpss_256);
 
 /*
  * Intel 5000 and 5100 Memory controllers have an erratum with read completion
@@ -3702,7 +3742,7 @@ DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL,
  * reset a single function if other methods (e.g. FLR, PM D0->D3) are
  * not available.
  */
-static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
+static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, bool probe)
 {
        /*
         * http://www.intel.com/content/dam/doc/datasheet/82599-10-gbe-controller-datasheet.pdf
@@ -3724,7 +3764,7 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
 #define NSDE_PWR_STATE         0xd0100
 #define IGD_OPERATION_TIMEOUT  10000     /* set timeout 10 seconds */
 
-static int reset_ivb_igd(struct pci_dev *dev, int probe)
+static int reset_ivb_igd(struct pci_dev *dev, bool probe)
 {
        void __iomem *mmio_base;
        unsigned long timeout;
@@ -3767,7 +3807,7 @@ reset_complete:
 }
 
 /* Device-specific reset method for Chelsio T4-based adapters */
-static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
+static int reset_chelsio_generic_dev(struct pci_dev *dev, bool probe)
 {
        u16 old_command;
        u16 msix_flags;
@@ -3845,14 +3885,14 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
  *    Chapter 3: NVMe control registers
  *    Chapter 7.3: Reset behavior
  */
-static int nvme_disable_and_flr(struct pci_dev *dev, int probe)
+static int nvme_disable_and_flr(struct pci_dev *dev, bool probe)
 {
        void __iomem *bar;
        u16 cmd;
        u32 cfg;
 
        if (dev->class != PCI_CLASS_STORAGE_EXPRESS ||
-           !pcie_has_flr(dev) || !pci_resource_start(dev, 0))
+           pcie_reset_flr(dev, PCI_RESET_PROBE) || !pci_resource_start(dev, 0))
                return -ENOTTY;
 
        if (probe)
@@ -3919,15 +3959,12 @@ static int nvme_disable_and_flr(struct pci_dev *dev, int probe)
  * device too soon after FLR.  A 250ms delay after FLR has heuristically
  * proven to produce reliably working results for device assignment cases.
  */
-static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
+static int delay_250ms_after_flr(struct pci_dev *dev, bool probe)
 {
-       if (!pcie_has_flr(dev))
-               return -ENOTTY;
-
        if (probe)
-               return 0;
+               return pcie_reset_flr(dev, PCI_RESET_PROBE);
 
-       pcie_flr(dev);
+       pcie_reset_flr(dev, PCI_RESET_DO_RESET);
 
        msleep(250);
 
@@ -3942,7 +3979,7 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
 #define HINIC_OPERATION_TIMEOUT     15000      /* 15 seconds */
 
 /* Device-specific reset method for Huawei Intelligent NIC virtual functions */
-static int reset_hinic_vf_dev(struct pci_dev *pdev, int probe)
+static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
 {
        unsigned long timeout;
        void __iomem *bar;
@@ -4019,7 +4056,7 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
  * because when a host assigns a device to a guest VM, the host may need
  * to reset the device but probably doesn't have a driver for it.
  */
-int pci_dev_specific_reset(struct pci_dev *dev, int probe)
+int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
 {
        const struct pci_dev_reset_methods *i;
 
@@ -5678,7 +5715,7 @@ static void quirk_reset_lenovo_thinkpad_p50_nvgpu(struct pci_dev *pdev)
 
        if (pdev->subsystem_vendor != PCI_VENDOR_ID_LENOVO ||
            pdev->subsystem_device != 0x222e ||
-           !pdev->reset_fn)
+           !pci_reset_supported(pdev))
                return;
 
        if (pci_enable_device_mem(pdev))
index dd12c2fcc7dc106da8e9a25fb3db0566ab668b63..4c54c75050dc12179b53d82425699715d7ad3597 100644 (file)
@@ -19,7 +19,6 @@ static void pci_stop_dev(struct pci_dev *dev)
        pci_pme_active(dev, false);
 
        if (pci_dev_is_added(dev)) {
-               dev->reset_fn = 0;
 
                device_release_driver(&dev->dev);
                pci_proc_detach_device(dev);
index 8b003c890b87b02389e4659ff08fbd9569fad96e..61a6fe3cde21cf227c7cc34529576758f801e4b5 100644 (file)
@@ -19,11 +19,12 @@ SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
        u8 byte;
        u16 word;
        u32 dword;
-       long err;
-       int cfg_ret;
+       int err, cfg_ret;
 
+       err = -EPERM;
+       dev = NULL;
        if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
+               goto error;
 
        err = -ENODEV;
        dev = pci_get_domain_bus_and_slot(0, bus, dfn);
index 540b377ca8f61c10b36bee14b4e28ad3b0e67748..85801c6375f2fd7535e3fb2a325c05929eaa2b5f 100644 (file)
                               PCI_STATUS_SIG_TARGET_ABORT | \
                               PCI_STATUS_PARITY)
 
+/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
+#define PCI_NUM_RESET_METHODS 7
+
+#define PCI_RESET_PROBE                true
+#define PCI_RESET_DO_RESET     false
+
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
@@ -333,6 +339,7 @@ struct pci_dev {
        struct rcec_ea  *rcec_ea;       /* RCEC cached endpoint association */
        struct pci_dev  *rcec;          /* Associated RCEC device */
 #endif
+       u32             devcap;         /* PCIe Device Capabilities */
        u8              pcie_cap;       /* PCIe capability offset */
        u8              msi_cap;        /* MSI capability offset */
        u8              msix_cap;       /* MSI-X capability offset */
@@ -388,6 +395,7 @@ struct pci_dev {
                                           supported from root to here */
        u16             l1ss;           /* L1SS Capability pointer */
 #endif
+       unsigned int    pasid_no_tlp:1;         /* PASID works without TLP Prefix */
        unsigned int    eetlp_prefix_path:1;    /* End-to-End TLP Prefix */
 
        pci_channel_state_t error_state;        /* Current connectivity state */
@@ -427,7 +435,6 @@ struct pci_dev {
        unsigned int    state_saved:1;
        unsigned int    is_physfn:1;
        unsigned int    is_virtfn:1;
-       unsigned int    reset_fn:1;
        unsigned int    is_hotplug_bridge:1;
        unsigned int    shpc_managed:1;         /* SHPC owned by shpchp */
        unsigned int    is_thunderbolt:1;       /* Thunderbolt controller */
@@ -505,6 +512,9 @@ struct pci_dev {
        char            *driver_override; /* Driver name to force a match */
 
        unsigned long   priv_flags;     /* Private flags for the PCI driver */
+
+       /* These methods index pci_reset_fn_methods[] */
+       u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */
 };
 
 static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
@@ -1228,7 +1238,7 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
                             enum pci_bus_speed *speed,
                             enum pcie_link_width *width);
 void pcie_print_link_status(struct pci_dev *dev);
-bool pcie_has_flr(struct pci_dev *dev);
+int pcie_reset_flr(struct pci_dev *dev, bool probe);
 int pcie_flr(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
@@ -1881,9 +1891,7 @@ int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma);
 #define pci_resource_end(dev, bar)     ((dev)->resource[(bar)].end)
 #define pci_resource_flags(dev, bar)   ((dev)->resource[(bar)].flags)
 #define pci_resource_len(dev,bar) \
-       ((pci_resource_start((dev), (bar)) == 0 &&      \
-         pci_resource_end((dev), (bar)) ==             \
-         pci_resource_start((dev), (bar))) ? 0 :       \
+       ((pci_resource_end((dev), (bar)) == 0) ? 0 :    \
                                                        \
         (pci_resource_end((dev), (bar)) -              \
          pci_resource_start((dev), (bar)) + 1))
index 2dac431d94ac141edfa05b387c62258cce0db86c..3a10d6ec3ee7f9618418a4e8394de3e096c72c1a 100644 (file)
@@ -44,7 +44,7 @@ struct hotplug_slot_ops {
        int (*get_attention_status)     (struct hotplug_slot *slot, u8 *value);
        int (*get_latch_status)         (struct hotplug_slot *slot, u8 *value);
        int (*get_adapter_status)       (struct hotplug_slot *slot, u8 *value);
-       int (*reset_slot)               (struct hotplug_slot *slot, int probe);
+       int (*reset_slot)               (struct hotplug_slot *slot, bool probe);
 };
 
 /**