Merge branch 'pci/misc' into next
authorBjorn Helgaas <bhelgaas@google.com>
Thu, 29 Aug 2013 23:23:33 +0000 (17:23 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 29 Aug 2013 23:23:33 +0000 (17:23 -0600)
* pci/misc:
  PCI/ACPI: Fix _OSC ordering to allow PCIe hotplug use when available
  PCI: exynos: Add I/O access wrappers
  PCI: designware: Drop "addr" arg from dw_pcie_readl_rc()/dw_pcie_writel_rc()

26 files changed:
arch/arm/kernel/bios32.c
arch/m68k/platform/coldfire/pci.c
arch/mips/pci/pci.c
arch/powerpc/kernel/pci-common.c
arch/sh/drivers/pci/pci.c
arch/tile/kernel/pci_gx.c
arch/x86/pci/acpi.c
drivers/acpi/pci_root.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/parisc/lba_pci.c
drivers/pci/bus.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pcihp_slot.c
drivers/pci/pci.c
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/pcmcia/cardbus.c
include/linux/pci.h
include/linux/pci_hotplug.h

index 261fcc8261698391937343d0f24ae4b72a93c0e7..88e14d74b6de8ae4cd21010e29e7ba421e80bdd0 100644 (file)
@@ -525,11 +525,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
                         * Assign resources.
                         */
                        pci_bus_assign_resources(bus);
-
-                       /*
-                        * Enable bridges
-                        */
-                       pci_enable_bridges(bus);
                }
 
                /*
index b33f97a13e6d11650db6f5a183511356884ae51e..df9679238b6d20f480487040abe882cc41ae4cba 100644 (file)
@@ -319,7 +319,6 @@ static int __init mcf_pci_init(void)
        pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
        pci_bus_size_bridges(rootbus);
        pci_bus_assign_resources(rootbus);
-       pci_enable_bridges(rootbus);
        return 0;
 }
 
index 594e60d6a43b256d5f65f04e751f624610b41b3d..33e7aa52d9c4451ca352221921e27c134246a52d 100644 (file)
@@ -113,7 +113,6 @@ static void pcibios_scanbus(struct pci_controller *hose)
                if (!pci_has_flag(PCI_PROBE_ONLY)) {
                        pci_bus_size_bridges(bus);
                        pci_bus_assign_resources(bus);
-                       pci_enable_bridges(bus);
                }
        }
 }
index f46914a0f33ea6fd3cacbdddb76288722dfb42cb..d35ec34de1b49c6d94e693aa0ea4286338332da8 100644 (file)
@@ -1672,12 +1672,8 @@ void pcibios_scan_phb(struct pci_controller *hose)
        /* Configure PCI Express settings */
        if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
                struct pci_bus *child;
-               list_for_each_entry(child, &bus->children, node) {
-                       struct pci_dev *self = child->self;
-                       if (!self)
-                               continue;
-                       pcie_bus_configure_settings(child, self->pcie_mpss);
-               }
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child);
        }
 }
 
index 102f5d58b0371ac512af95a4d8994b91ad53a227..60ed3e1c4b753dd92ba4c58cc59def3079ef2050 100644 (file)
@@ -69,7 +69,6 @@ static void pcibios_scanbus(struct pci_channel *hose)
 
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
-               pci_enable_bridges(bus);
        } else {
                pci_free_resource_list(&resources);
        }
index 11425633b2d7a03e2b04cadf144fbde7efe585cf..6640e7bbeaa286499d112f8efe35ab383249c5d0 100644 (file)
@@ -508,13 +508,8 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller)
                                                rc_dev_cap.word);
 
        /* Configure PCI Express MPS setting. */
-       list_for_each_entry(child, &root_bus->children, node) {
-               struct pci_dev *self = child->self;
-               if (!self)
-                       continue;
-
-               pcie_bus_configure_settings(child, self->pcie_mpss);
-       }
+       list_for_each_entry(child, &root_bus->children, node)
+               pcie_bus_configure_settings(child);
 
        /*
         * Set the mac_config register in trio based on the MPS/MRS of the link.
index d641897a1f4e5d53a5f14ec3e25b7517fe3d8b9f..b30e937689d617cee4b37775f70bc8e001af0441 100644 (file)
@@ -568,13 +568,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
         */
        if (bus) {
                struct pci_bus *child;
-               list_for_each_entry(child, &bus->children, node) {
-                       struct pci_dev *self = child->self;
-                       if (!self)
-                               continue;
-
-                       pcie_bus_configure_settings(child, self->pcie_mpss);
-               }
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child);
        }
 
        if (bus && node != -1) {
index a67853e3c419f017bffdc3134d269b61575b7567..d3874f4256534d06aeb0fdb9f364e5f5851963f3 100644 (file)
@@ -540,10 +540,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
 
        if (system_state != SYSTEM_BOOTING) {
                pcibios_resource_survey_bus(root->bus);
-               pci_assign_unassigned_bus_resources(root->bus);
-
-               /* need to after hot-added ioapic is registered */
-               pci_enable_bridges(root->bus);
+               pci_assign_unassigned_root_bus_resources(root->bus);
        }
 
        pci_bus_add_devices(root->bus);
index e5da07858a2f0d5dca0747e1b7fe58992b799d5e..c51d2f82a93ebe3be5584f2e46ef8156fda9febe 100644 (file)
@@ -9935,8 +9935,6 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
 
 static int bnx2x_do_flr(struct bnx2x *bp)
 {
-       int i;
-       u16 status;
        struct pci_dev *dev = bp->pdev;
 
        if (CHIP_IS_E1x(bp)) {
@@ -9951,20 +9949,8 @@ static int bnx2x_do_flr(struct bnx2x *bp)
                return -EINVAL;
        }
 
-       /* Wait for Transaction Pending bit clean */
-       for (i = 0; i < 4; i++) {
-               if (i)
-                       msleep((1 << (i - 1)) * 100);
-
-               pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
-               if (!(status & PCI_EXP_DEVSTA_TRPND))
-                       goto clear;
-       }
-
-       dev_err(&dev->dev,
-               "transaction is not cleared; proceeding with reset anyway\n");
-
-clear:
+       if (!pci_wait_for_pending_transaction(dev))
+               dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
 
        BNX2X_DEV_INFO("Initiating FLR\n");
        bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0);
index 19f6f70c67d398f8d585618901de98797ebbfcef..37e71ff6408dca41ff5790417f549eead9ddea97 100644 (file)
@@ -1590,7 +1590,6 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
        }
-       pci_enable_bridges(lba_bus);
 
        /*
        ** Once PCI register ops has walked the bus, access to config
index b1ff02ab4f131fbda7edd9971342b9ae91bf4149..fc1b740137430b703a348b03d1c9420d19d21d7a 100644 (file)
@@ -216,24 +216,6 @@ void pci_bus_add_devices(const struct pci_bus *bus)
        }
 }
 
-void pci_enable_bridges(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-       int retval;
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               if (dev->subordinate) {
-                       if (!pci_is_enabled(dev)) {
-                               retval = pci_enable_device(dev);
-                               if (retval)
-                                       dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", retval);
-                               pci_set_master(dev);
-                       }
-                       pci_enable_bridges(dev->subordinate);
-               }
-       }
-}
-
 /** pci_walk_bus - walk devices on/under bus, calling callback.
  *  @top      bus whose devices should be walked
  *  @cb       callback to be called for each device found
@@ -301,4 +283,3 @@ EXPORT_SYMBOL(pci_bus_put);
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);
-EXPORT_SYMBOL(pci_enable_bridges);
index 59df8575a48ce834fb48ea002689ed97ed9ca51a..52dee9d31e1cad6070b8e78b0eb507dc39a4f16f 100644 (file)
@@ -723,7 +723,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        acpiphp_sanitize_bus(bus);
        acpiphp_set_hpp_values(bus);
        acpiphp_set_acpi_region(slot);
-       pci_enable_bridges(bus);
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                /* Assume that newly added devices are powered on already. */
index 7fb326983ed69a1a1c0796ab32cbd05c9200100c..541bbe6d5343e9c99da97f9e5fd8c74c554b24d3 100644 (file)
@@ -155,6 +155,7 @@ void pciehp_green_led_off(struct slot *slot);
 void pciehp_green_led_blink(struct slot *slot);
 int pciehp_check_link_status(struct controller *ctrl);
 void pciehp_release_ctrl(struct controller *ctrl);
+int pciehp_reset_slot(struct slot *slot, int probe);
 
 static inline const char *slot_name(struct slot *slot)
 {
index 7d72c5e2eba90cc98cb233142ba6baadd778d9ae..f4a18f51a29cc3bc1c17121ab265ce9e199da0ec 100644 (file)
@@ -69,6 +69,7 @@ static int get_power_status   (struct hotplug_slot *slot, u8 *value);
 static int get_attention_status        (struct hotplug_slot *slot, u8 *value);
 static int get_latch_status    (struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status  (struct hotplug_slot *slot, u8 *value);
+static int reset_slot          (struct hotplug_slot *slot, int probe);
 
 /**
  * release_slot - free up the memory used by a slot
@@ -111,6 +112,7 @@ static int init_slot(struct controller *ctrl)
        ops->disable_slot = disable_slot;
        ops->get_power_status = get_power_status;
        ops->get_adapter_status = get_adapter_status;
+       ops->reset_slot = reset_slot;
        if (MRL_SENS(ctrl))
                ops->get_latch_status = get_latch_status;
        if (ATTN_LED(ctrl)) {
@@ -223,6 +225,16 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
        return pciehp_get_adapter_status(slot, value);
 }
 
+static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
+{
+       struct slot *slot = hotplug_slot->private;
+
+       ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
+                __func__, slot_name(slot));
+
+       return pciehp_reset_slot(slot, probe);
+}
+
 static int pciehp_probe(struct pcie_device *dev)
 {
        int rc;
index b2255736ac81fa819e651f40deb17a6102c4240a..51f56ef4ab6f83a9382527f9061172800fff589a 100644 (file)
@@ -749,6 +749,37 @@ static void pcie_disable_notification(struct controller *ctrl)
                ctrl_warn(ctrl, "Cannot disable software notification\n");
 }
 
+/*
+ * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
+ * bus reset of the bridge, but if the slot supports surprise removal we need
+ * to disable presence detection around the bus reset and clear any spurious
+ * events after.
+ */
+int pciehp_reset_slot(struct slot *slot, int probe)
+{
+       struct controller *ctrl = slot->ctrl;
+
+       if (probe)
+               return 0;
+
+       if (HP_SUPR_RM(ctrl)) {
+               pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
+               if (pciehp_poll_mode)
+                       del_timer_sync(&ctrl->poll_timer);
+       }
+
+       pci_reset_bridge_secondary_bus(ctrl->pcie->port);
+
+       if (HP_SUPR_RM(ctrl)) {
+               pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDC);
+               pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
+               if (pciehp_poll_mode)
+                       int_poll_timeout(ctrl->poll_timer.data);
+       }
+
+       return 0;
+}
+
 int pcie_init_notification(struct controller *ctrl)
 {
        if (pciehp_request_irq(ctrl))
index fec2d5b754401ddd63d402c49b0a11c039f325ff..16f9203523179c46e99505443675c964f16f4b1a 100644 (file)
@@ -160,9 +160,8 @@ void pci_configure_slot(struct pci_dev *dev)
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
                return;
 
-       if (dev->bus && dev->bus->self)
-               pcie_bus_configure_settings(dev->bus,
-                                           dev->bus->self->pcie_mpss);
+       if (dev->bus)
+               pcie_bus_configure_settings(dev->bus);
 
        memset(&hpp, 0, sizeof(hpp));
        ret = pci_get_hp_params(dev, &hpp);
index 3d5d45cdc4ddc4409f69a10d6b85e4bb7bddfd2e..b821a62958fd9623df047c318085c761465282da 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pci_hotplug.h>
 #include <asm-generic/pci-bridge.h>
 #include <asm/setup.h>
 #include "pci.h"
@@ -1145,6 +1146,24 @@ int pci_reenable_device(struct pci_dev *dev)
        return 0;
 }
 
+static void pci_enable_bridge(struct pci_dev *dev)
+{
+       int retval;
+
+       if (!dev)
+               return;
+
+       pci_enable_bridge(dev->bus->self);
+
+       if (pci_is_enabled(dev))
+               return;
+       retval = pci_enable_device(dev);
+       if (retval)
+               dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n",
+                       retval);
+       pci_set_master(dev);
+}
+
 static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
 {
        int err;
@@ -1165,6 +1184,8 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
        if (atomic_inc_return(&dev->enable_cnt) > 1)
                return 0;               /* already enabled */
 
+       pci_enable_bridge(dev->bus->self);
+
        /* only skip sriov related */
        for (i = 0; i <= PCI_ROM_RESOURCE; i++)
                if (dev->resource[i].flags & flags)
@@ -2362,6 +2383,27 @@ void pci_enable_acs(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
 }
 
+static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+       int pos;
+       u16 cap, ctrl;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+       if (!pos)
+               return false;
+
+       /*
+        * Except for egress control, capabilities are either required
+        * or only required if controllable.  Features missing from the
+        * capability field can therefore be assumed as hard-wired enabled.
+        */
+       pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap);
+       acs_flags &= (cap | PCI_ACS_EC);
+
+       pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+       return (ctrl & acs_flags) == acs_flags;
+}
+
 /**
  * pci_acs_enabled - test ACS against required flags for a given device
  * @pdev: device to test
@@ -2369,36 +2411,76 @@ void pci_enable_acs(struct pci_dev *dev)
  *
  * Return true if the device supports the provided flags.  Automatically
  * filters out flags that are not implemented on multifunction devices.
+ *
+ * Note that this interface checks the effective ACS capabilities of the
+ * device rather than the actual capabilities.  For instance, most single
+ * function endpoints are not required to support ACS because they have no
+ * opportunity for peer-to-peer access.  We therefore return 'true'
+ * regardless of whether the device exposes an ACS capability.  This makes
+ * it much easier for callers of this function to ignore the actual type
+ * or topology of the device when testing ACS support.
  */
 bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
 {
-       int pos, ret;
-       u16 ctrl;
+       int ret;
 
        ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
        if (ret >= 0)
                return ret > 0;
 
+       /*
+        * Conventional PCI and PCI-X devices never support ACS, either
+        * effectively or actually.  The shared bus topology implies that
+        * any device on the bus can receive or snoop DMA.
+        */
        if (!pci_is_pcie(pdev))
                return false;
 
-       /* Filter out flags not applicable to multifunction */
-       if (pdev->multifunction)
-               acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
-                             PCI_ACS_EC | PCI_ACS_DT);
-
-       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM ||
-           pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
-           pdev->multifunction) {
-               pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
-               if (!pos)
-                       return false;
+       switch (pci_pcie_type(pdev)) {
+       /*
+        * PCI/X-to-PCIe bridges are not specifically mentioned by the spec,
+        * but since their primary inteface is PCI/X, we conservatively
+        * handle them as we would a non-PCIe device.
+        */
+       case PCI_EXP_TYPE_PCIE_BRIDGE:
+       /*
+        * PCIe 3.0, 6.12.1 excludes ACS on these devices.  "ACS is never
+        * applicable... must never implement an ACS Extended Capability...".
+        * This seems arbitrary, but we take a conservative interpretation
+        * of this statement.
+        */
+       case PCI_EXP_TYPE_PCI_BRIDGE:
+       case PCI_EXP_TYPE_RC_EC:
+               return false;
+       /*
+        * PCIe 3.0, 6.12.1.1 specifies that downstream and root ports should
+        * implement ACS in order to indicate their peer-to-peer capabilities,
+        * regardless of whether they are single- or multi-function devices.
+        */
+       case PCI_EXP_TYPE_DOWNSTREAM:
+       case PCI_EXP_TYPE_ROOT_PORT:
+               return pci_acs_flags_enabled(pdev, acs_flags);
+       /*
+        * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be
+        * implemented by the remaining PCIe types to indicate peer-to-peer
+        * capabilities, but only when they are part of a multifunciton
+        * device.  The footnote for section 6.12 indicates the specific
+        * PCIe types included here.
+        */
+       case PCI_EXP_TYPE_ENDPOINT:
+       case PCI_EXP_TYPE_UPSTREAM:
+       case PCI_EXP_TYPE_LEG_END:
+       case PCI_EXP_TYPE_RC_END:
+               if (!pdev->multifunction)
+                       break;
 
-               pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
-               if ((ctrl & acs_flags) != acs_flags)
-                       return false;
+               return pci_acs_flags_enabled(pdev, acs_flags);
        }
 
+       /*
+        * PCIe 3.0, 6.12.1.3 specifies no ACS capabilties are applicable
+        * to single function devices with the exception of downstream ports.
+        */
        return true;
 }
 
@@ -3106,19 +3188,17 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
 }
 EXPORT_SYMBOL(pci_set_dma_seg_boundary);
 
-static int pcie_flr(struct pci_dev *dev, int probe)
+/**
+ * pci_wait_for_pending_transaction - waits for pending transaction
+ * @dev: the PCI device to operate on
+ *
+ * Return 0 if transaction is pending 1 otherwise.
+ */
+int pci_wait_for_pending_transaction(struct pci_dev *dev)
 {
        int i;
-       u32 cap;
        u16 status;
 
-       pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
-       if (!(cap & PCI_EXP_DEVCAP_FLR))
-               return -ENOTTY;
-
-       if (probe)
-               return 0;
-
        /* Wait for Transaction Pending bit clean */
        for (i = 0; i < 4; i++) {
                if (i)
@@ -3126,13 +3206,27 @@ static int pcie_flr(struct pci_dev *dev, int probe)
 
                pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
                if (!(status & PCI_EXP_DEVSTA_TRPND))
-                       goto clear;
+                       return 1;
        }
 
-       dev_err(&dev->dev, "transaction is not cleared; "
-                       "proceeding with reset anyway\n");
+       return 0;
+}
+EXPORT_SYMBOL(pci_wait_for_pending_transaction);
+
+static int pcie_flr(struct pci_dev *dev, int probe)
+{
+       u32 cap;
+
+       pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
+       if (!(cap & PCI_EXP_DEVCAP_FLR))
+               return -ENOTTY;
+
+       if (probe)
+               return 0;
+
+       if (!pci_wait_for_pending_transaction(dev))
+               dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
 
-clear:
        pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
        msleep(100);
@@ -3223,9 +3317,42 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
        return 0;
 }
 
-static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+/**
+ * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
+ * @dev: Bridge device
+ *
+ * Use the bridge control register to assert reset on the secondary bus.
+ * Devices on the secondary bus are left in power-on state.
+ */
+void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
 {
        u16 ctrl;
+
+       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+       ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+       /*
+        * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms.  Double
+        * this to 2ms to ensure that we meet the minium requirement.
+        */
+       msleep(2);
+
+       ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+       /*
+        * Trhfa for conventional PCI is 2^25 clock cycles.
+        * Assuming a minimum 33MHz clock this results in a 1s
+        * delay before we can consider subordinate devices to
+        * be re-initialized.  PCIe has some ways to shorten this,
+        * but we don't make use of them yet.
+        */
+       ssleep(1);
+}
+EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
+
+static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+{
        struct pci_dev *pdev;
 
        if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
@@ -3238,18 +3365,40 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
        if (probe)
                return 0;
 
-       pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl);
-       ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
-       msleep(100);
-
-       ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
-       msleep(100);
+       pci_reset_bridge_secondary_bus(dev->bus->self);
 
        return 0;
 }
 
+static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
+{
+       int rc = -ENOTTY;
+
+       if (!hotplug || !try_module_get(hotplug->ops->owner))
+               return rc;
+
+       if (hotplug->ops->reset_slot)
+               rc = hotplug->ops->reset_slot(hotplug, probe);
+
+       module_put(hotplug->ops->owner);
+
+       return rc;
+}
+
+static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
+{
+       struct pci_dev *pdev;
+
+       if (dev->subordinate || !dev->slot)
+               return -ENOTTY;
+
+       list_for_each_entry(pdev, &dev->bus->devices, bus_list)
+               if (pdev != dev && pdev->slot == dev->slot)
+                       return -ENOTTY;
+
+       return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
+}
+
 static int __pci_dev_reset(struct pci_dev *dev, int probe)
 {
        int rc;
@@ -3272,27 +3421,65 @@ static int __pci_dev_reset(struct pci_dev *dev, int probe)
        if (rc != -ENOTTY)
                goto done;
 
+       rc = pci_dev_reset_slot_function(dev, probe);
+       if (rc != -ENOTTY)
+               goto done;
+
        rc = pci_parent_bus_reset(dev, probe);
 done:
        return rc;
 }
 
+static void pci_dev_lock(struct pci_dev *dev)
+{
+       pci_cfg_access_lock(dev);
+       /* block PM suspend, driver probe, etc. */
+       device_lock(&dev->dev);
+}
+
+static void pci_dev_unlock(struct pci_dev *dev)
+{
+       device_unlock(&dev->dev);
+       pci_cfg_access_unlock(dev);
+}
+
+static void pci_dev_save_and_disable(struct pci_dev *dev)
+{
+       /*
+        * Wake-up device prior to save.  PM registers default to D0 after
+        * reset and a simple register restore doesn't reliably return
+        * to a non-D0 state anyway.
+        */
+       pci_set_power_state(dev, PCI_D0);
+
+       pci_save_state(dev);
+       /*
+        * Disable the device by clearing the Command register, except for
+        * INTx-disable which is set.  This not only disables MMIO and I/O port
+        * BARs, but also prevents the device from being Bus Master, preventing
+        * DMA from the device including MSI/MSI-X interrupts.  For PCI 2.3
+        * compliant devices, INTx-disable prevents legacy interrupts.
+        */
+       pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+}
+
+static void pci_dev_restore(struct pci_dev *dev)
+{
+       pci_restore_state(dev);
+}
+
 static int pci_dev_reset(struct pci_dev *dev, int probe)
 {
        int rc;
 
-       if (!probe) {
-               pci_cfg_access_lock(dev);
-               /* block PM suspend, driver probe, etc. */
-               device_lock(&dev->dev);
-       }
+       if (!probe)
+               pci_dev_lock(dev);
 
        rc = __pci_dev_reset(dev, probe);
 
-       if (!probe) {
-               device_unlock(&dev->dev);
-               pci_cfg_access_unlock(dev);
-       }
+       if (!probe)
+               pci_dev_unlock(dev);
+
        return rc;
 }
 /**
@@ -3383,22 +3570,249 @@ int pci_reset_function(struct pci_dev *dev)
        if (rc)
                return rc;
 
-       pci_save_state(dev);
-
-       /*
-        * both INTx and MSI are disabled after the Interrupt Disable bit
-        * is set and the Bus Master bit is cleared.
-        */
-       pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+       pci_dev_save_and_disable(dev);
 
        rc = pci_dev_reset(dev, 0);
 
-       pci_restore_state(dev);
+       pci_dev_restore(dev);
 
        return rc;
 }
 EXPORT_SYMBOL_GPL(pci_reset_function);
 
+/* Lock devices from the top of the tree down */
+static void pci_bus_lock(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               pci_dev_lock(dev);
+               if (dev->subordinate)
+                       pci_bus_lock(dev->subordinate);
+       }
+}
+
+/* Unlock devices from the bottom of the tree up */
+static void pci_bus_unlock(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (dev->subordinate)
+                       pci_bus_unlock(dev->subordinate);
+               pci_dev_unlock(dev);
+       }
+}
+
+/* Lock devices from the top of the tree down */
+static void pci_slot_lock(struct pci_slot *slot)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+               if (!dev->slot || dev->slot != slot)
+                       continue;
+               pci_dev_lock(dev);
+               if (dev->subordinate)
+                       pci_bus_lock(dev->subordinate);
+       }
+}
+
+/* Unlock devices from the bottom of the tree up */
+static void pci_slot_unlock(struct pci_slot *slot)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+               if (!dev->slot || dev->slot != slot)
+                       continue;
+               if (dev->subordinate)
+                       pci_bus_unlock(dev->subordinate);
+               pci_dev_unlock(dev);
+       }
+}
+
+/* Save and disable devices from the top of the tree down */
+static void pci_bus_save_and_disable(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               pci_dev_save_and_disable(dev);
+               if (dev->subordinate)
+                       pci_bus_save_and_disable(dev->subordinate);
+       }
+}
+
+/*
+ * Restore devices from top of the tree down - parent bridges need to be
+ * restored before we can get to subordinate devices.
+ */
+static void pci_bus_restore(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               pci_dev_restore(dev);
+               if (dev->subordinate)
+                       pci_bus_restore(dev->subordinate);
+       }
+}
+
+/* Save and disable devices from the top of the tree down */
+static void pci_slot_save_and_disable(struct pci_slot *slot)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+               if (!dev->slot || dev->slot != slot)
+                       continue;
+               pci_dev_save_and_disable(dev);
+               if (dev->subordinate)
+                       pci_bus_save_and_disable(dev->subordinate);
+       }
+}
+
+/*
+ * Restore devices from top of the tree down - parent bridges need to be
+ * restored before we can get to subordinate devices.
+ */
+static void pci_slot_restore(struct pci_slot *slot)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+               if (!dev->slot || dev->slot != slot)
+                       continue;
+               pci_dev_restore(dev);
+               if (dev->subordinate)
+                       pci_bus_restore(dev->subordinate);
+       }
+}
+
+static int pci_slot_reset(struct pci_slot *slot, int probe)
+{
+       int rc;
+
+       if (!slot)
+               return -ENOTTY;
+
+       if (!probe)
+               pci_slot_lock(slot);
+
+       might_sleep();
+
+       rc = pci_reset_hotplug_slot(slot->hotplug, probe);
+
+       if (!probe)
+               pci_slot_unlock(slot);
+
+       return rc;
+}
+
+/**
+ * pci_probe_reset_slot - probe whether a PCI slot can be reset
+ * @slot: PCI slot to probe
+ *
+ * Return 0 if slot can be reset, negative if a slot reset is not supported.
+ */
+int pci_probe_reset_slot(struct pci_slot *slot)
+{
+       return pci_slot_reset(slot, 1);
+}
+EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
+
+/**
+ * pci_reset_slot - reset a PCI slot
+ * @slot: PCI slot to reset
+ *
+ * A PCI bus may host multiple slots, each slot may support a reset mechanism
+ * independent of other slots.  For instance, some slots may support slot power
+ * control.  In the case of a 1:1 bus to slot architecture, this function may
+ * wrap the bus reset to avoid spurious slot related events such as hotplug.
+ * Generally a slot reset should be attempted before a bus reset.  All of the
+ * function of the slot and any subordinate buses behind the slot are reset
+ * through this function.  PCI config space of all devices in the slot and
+ * behind the slot is saved before and restored after reset.
+ *
+ * Return 0 on success, non-zero on error.
+ */
+int pci_reset_slot(struct pci_slot *slot)
+{
+       int rc;
+
+       rc = pci_slot_reset(slot, 1);
+       if (rc)
+               return rc;
+
+       pci_slot_save_and_disable(slot);
+
+       rc = pci_slot_reset(slot, 0);
+
+       pci_slot_restore(slot);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pci_reset_slot);
+
+static int pci_bus_reset(struct pci_bus *bus, int probe)
+{
+       if (!bus->self)
+               return -ENOTTY;
+
+       if (probe)
+               return 0;
+
+       pci_bus_lock(bus);
+
+       might_sleep();
+
+       pci_reset_bridge_secondary_bus(bus->self);
+
+       pci_bus_unlock(bus);
+
+       return 0;
+}
+
+/**
+ * pci_probe_reset_bus - probe whether a PCI bus can be reset
+ * @bus: PCI bus to probe
+ *
+ * Return 0 if bus can be reset, negative if a bus reset is not supported.
+ */
+int pci_probe_reset_bus(struct pci_bus *bus)
+{
+       return pci_bus_reset(bus, 1);
+}
+EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
+
+/**
+ * pci_reset_bus - reset a PCI bus
+ * @bus: top level PCI bus to reset
+ *
+ * Do a bus reset on the given bus and any subordinate buses, saving
+ * and restoring state of all devices.
+ *
+ * Return 0 on success, non-zero on error.
+ */
+int pci_reset_bus(struct pci_bus *bus)
+{
+       int rc;
+
+       rc = pci_bus_reset(bus, 1);
+       if (rc)
+               return rc;
+
+       pci_bus_save_and_disable(bus);
+
+       rc = pci_bus_reset(bus, 0);
+
+       pci_bus_restore(bus);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pci_reset_bus);
+
 /**
  * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
  * @dev: PCI device to query
@@ -3533,8 +3947,6 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
        if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
                int mps = pcie_get_mps(dev);
 
-               if (mps < 0)
-                       return mps;
                if (mps < rq)
                        rq = mps;
        }
@@ -3551,7 +3963,6 @@ EXPORT_SYMBOL(pcie_set_readrq);
  * @dev: PCI device to query
  *
  * Returns maximum payload size in bytes
- *    or appropriate error value.
  */
 int pcie_get_mps(struct pci_dev *dev)
 {
index 76ef634caf6f169ec7ca506e7e3aec7434a9753e..0bf82a20a0fb479ccfbdb43479bf9b0cf6ecff6a 100644 (file)
@@ -352,7 +352,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
-       aer_do_secondary_bus_reset(dev);
+       pci_reset_bridge_secondary_bus(dev);
        dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 
        /* Clear Root Error Status */
index 90ea3e88041f74c25f3339d77cf8d4929784edfb..84420b7c9456ecbb0e43a9e8ca539af5b2ee1a20 100644 (file)
@@ -106,7 +106,6 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
 }
 
 extern struct bus_type pcie_port_bus_type;
-void aer_do_secondary_bus_reset(struct pci_dev *dev);
 int aer_init(struct pcie_device *dev);
 void aer_isr(struct work_struct *work);
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
index 8b68ae59b7b6446f6405291ac868df18fdccee7c..85ca36f2136d0008af72c4aa0ddbaa1b321855e7 100644 (file)
@@ -366,39 +366,6 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
        return result_data.result;
 }
 
-/**
- * aer_do_secondary_bus_reset - perform secondary bus reset
- * @dev: pointer to bridge's pci_dev data structure
- *
- * Invoked when performing link reset at Root Port or Downstream Port.
- */
-void aer_do_secondary_bus_reset(struct pci_dev *dev)
-{
-       u16 p2p_ctrl;
-
-       /* Assert Secondary Bus Reset */
-       pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
-       p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
-
-       /*
-        * we should send hot reset message for 2ms to allow it time to
-        * propagate to all downstream ports
-        */
-       msleep(2);
-
-       /* De-assert Secondary Bus Reset */
-       p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-       pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
-
-       /*
-        * System software must wait for at least 100ms from the end
-        * of a reset of one or more device before it is permitted
-        * to issue Configuration Requests to those devices.
-        */
-       msleep(200);
-}
-
 /**
  * default_reset_link - default reset function
  * @dev: pointer to pci_dev data structure
@@ -408,7 +375,7 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev)
  */
 static pci_ers_result_t default_reset_link(struct pci_dev *dev)
 {
-       aer_do_secondary_bus_reset(dev);
+       pci_reset_bridge_secondary_bus(dev);
        dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n");
        return PCI_ERS_RESULT_RECOVERED;
 }
index b50386dc72e0d58ca09f8fed68687af978105b40..eeb50bd624025e91e9b871559da7b4c9675d3422 100644 (file)
@@ -1496,24 +1496,23 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data)
        if (!pci_is_pcie(dev))
                return 0;
 
-       /* For PCIE hotplug enabled slots not connected directly to a
-        * PCI-E root port, there can be problems when hotplugging
-        * devices.  This is due to the possibility of hotplugging a
-        * device into the fabric with a smaller MPS that the devices
-        * currently running have configured.  Modifying the MPS on the
-        * running devices could cause a fatal bus error due to an
-        * incoming frame being larger than the newly configured MPS.
-        * To work around this, the MPS for the entire fabric must be
-        * set to the minimum size.  Any devices hotplugged into this
-        * fabric will have the minimum MPS set.  If the PCI hotplug
-        * slot is directly connected to the root port and there are not
-        * other devices on the fabric (which seems to be the most
-        * common case), then this is not an issue and MPS discovery
-        * will occur as normal.
+       /*
+        * We don't have a way to change MPS settings on devices that have
+        * drivers attached.  A hot-added device might support only the minimum
+        * MPS setting (MPS=128).  Therefore, if the fabric contains a bridge
+        * where devices may be hot-added, we limit the fabric MPS to 128 so
+        * hot-added devices will work correctly.
+        *
+        * However, if we hot-add a device to a slot directly below a Root
+        * Port, it's impossible for there to be other existing devices below
+        * the port.  We don't limit the MPS in this case because we can
+        * reconfigure MPS on both the Root Port and the hot-added device,
+        * and there are no other devices involved.
+        *
+        * Note that this PCIE_BUS_SAFE path assumes no peer-to-peer DMA.
         */
-       if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
-            (dev->bus->self &&
-             pci_pcie_type(dev->bus->self) != PCI_EXP_TYPE_ROOT_PORT)))
+       if (dev->is_hotplug_bridge &&
+           pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
                *smpss = 0;
 
        if (*smpss > dev->pcie_mpss)
@@ -1588,6 +1587,22 @@ static void pcie_write_mrrs(struct pci_dev *dev)
                        "with pci=pcie_bus_safe.\n");
 }
 
+static void pcie_bus_detect_mps(struct pci_dev *dev)
+{
+       struct pci_dev *bridge = dev->bus->self;
+       int mps, p_mps;
+
+       if (!bridge)
+               return;
+
+       mps = pcie_get_mps(dev);
+       p_mps = pcie_get_mps(bridge);
+
+       if (mps != p_mps)
+               dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n",
+                        mps, pci_name(bridge), p_mps);
+}
+
 static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
 {
        int mps, orig_mps;
@@ -1595,13 +1610,18 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
        if (!pci_is_pcie(dev))
                return 0;
 
+       if (pcie_bus_config == PCIE_BUS_TUNE_OFF) {
+               pcie_bus_detect_mps(dev);
+               return 0;
+       }
+
        mps = 128 << *(u8 *)data;
        orig_mps = pcie_get_mps(dev);
 
        pcie_write_mps(dev, mps);
        pcie_write_mrrs(dev);
 
-       dev_info(&dev->dev, "PCI-E Max Payload Size set to %4d/%4d (was %4d), "
+       dev_info(&dev->dev, "Max Payload Size set to %4d/%4d (was %4d), "
                 "Max Read Rq %4d\n", pcie_get_mps(dev), 128 << dev->pcie_mpss,
                 orig_mps, pcie_get_readrq(dev));
 
@@ -1612,25 +1632,25 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
  * parents then children fashion.  If this changes, then this code will not
  * work as designed.
  */
-void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
+void pcie_bus_configure_settings(struct pci_bus *bus)
 {
        u8 smpss;
 
-       if (!pci_is_pcie(bus->self))
+       if (!bus->self)
                return;
 
-       if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
+       if (!pci_is_pcie(bus->self))
                return;
 
        /* FIXME - Peer to peer DMA is possible, though the endpoint would need
-        * to be aware to the MPS of the destination.  To work around this,
+        * to be aware of the MPS of the destination.  To work around this,
         * simply force the MPS of the entire system to the smallest possible.
         */
        if (pcie_bus_config == PCIE_BUS_PEER2PEER)
                smpss = 0;
 
        if (pcie_bus_config == PCIE_BUS_SAFE) {
-               smpss = mpss;
+               smpss = bus->self->pcie_mpss;
 
                pcie_find_smpss(bus->self, &smpss);
                pci_walk_bus(bus, pcie_find_smpss, &smpss);
@@ -1984,7 +2004,6 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 
        max = pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return max;
index e85d23044ae0dcd43b20d0b840a71e551286a310..f6c31fabf3af0bbe24f20b949cc0b6373b11ab97 100644 (file)
@@ -3126,9 +3126,6 @@ static int reset_intel_generic_dev(struct pci_dev *dev, int probe)
 
 static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
 {
-       int i;
-       u16 status;
-
        /*
         * http://www.intel.com/content/dam/doc/datasheet/82599-10-gbe-controller-datasheet.pdf
         *
@@ -3140,20 +3137,9 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
        if (probe)
                return 0;
 
-       /* Wait for Transaction Pending bit clean */
-       for (i = 0; i < 4; i++) {
-               if (i)
-                       msleep((1 << (i - 1)) * 100);
-
-               pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
-               if (!(status & PCI_EXP_DEVSTA_TRPND))
-                       goto clear;
-       }
-
-       dev_err(&dev->dev, "transaction is not cleared; "
-                       "proceeding with reset anyway\n");
+       if (!pci_wait_for_pending_transaction(dev))
+               dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
 
-clear:
        pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
        msleep(100);
@@ -3208,6 +3194,83 @@ reset_complete:
        return 0;
 }
 
+/*
+ * Device-specific reset method for Chelsio T4-based adapters.
+ */
+static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
+{
+       u16 old_command;
+       u16 msix_flags;
+
+       /*
+        * If this isn't a Chelsio T4-based device, return -ENOTTY indicating
+        * that we have no device-specific reset method.
+        */
+       if ((dev->device & 0xf000) != 0x4000)
+               return -ENOTTY;
+
+       /*
+        * If this is the "probe" phase, return 0 indicating that we can
+        * reset this device.
+        */
+       if (probe)
+               return 0;
+
+       /*
+        * T4 can wedge if there are DMAs in flight within the chip and Bus
+        * Master has been disabled.  We need to have it on till the Function
+        * Level Reset completes.  (BUS_MASTER is disabled in
+        * pci_reset_function()).
+        */
+       pci_read_config_word(dev, PCI_COMMAND, &old_command);
+       pci_write_config_word(dev, PCI_COMMAND,
+                             old_command | PCI_COMMAND_MASTER);
+
+       /*
+        * Perform the actual device function reset, saving and restoring
+        * configuration information around the reset.
+        */
+       pci_save_state(dev);
+
+       /*
+        * T4 also suffers a Head-Of-Line blocking problem if MSI-X interrupts
+        * are disabled when an MSI-X interrupt message needs to be delivered.
+        * So we briefly re-enable MSI-X interrupts for the duration of the
+        * FLR.  The pci_restore_state() below will restore the original
+        * MSI-X state.
+        */
+       pci_read_config_word(dev, dev->msix_cap+PCI_MSIX_FLAGS, &msix_flags);
+       if ((msix_flags & PCI_MSIX_FLAGS_ENABLE) == 0)
+               pci_write_config_word(dev, dev->msix_cap+PCI_MSIX_FLAGS,
+                                     msix_flags |
+                                     PCI_MSIX_FLAGS_ENABLE |
+                                     PCI_MSIX_FLAGS_MASKALL);
+
+       /*
+        * Start of pcie_flr() code sequence.  This reset code is a copy of
+        * the guts of pcie_flr() because that's not an exported function.
+        */
+
+       if (!pci_wait_for_pending_transaction(dev))
+               dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
+
+       pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
+       msleep(100);
+
+       /*
+        * End of pcie_flr() code sequence.
+        */
+
+       /*
+        * Restore the configuration information (BAR values, etc.) including
+        * the original PCI Configuration Space Command word, and return
+        * success.
+        */
+       pci_restore_state(dev);
+       pci_write_config_word(dev, PCI_COMMAND, old_command);
+       return 0;
+}
+
 #define PCI_DEVICE_ID_INTEL_82599_SFP_VF   0x10ed
 #define PCI_DEVICE_ID_INTEL_IVB_M_VGA      0x0156
 #define PCI_DEVICE_ID_INTEL_IVB_M2_VGA     0x0166
@@ -3221,6 +3284,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
                reset_ivb_igd },
        { PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
                reset_intel_generic_dev },
+       { PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+               reset_chelsio_generic_dev },
        { 0 }
 };
 
@@ -3295,11 +3360,61 @@ struct pci_dev *pci_get_dma_source(struct pci_dev *dev)
        return pci_dev_get(dev);
 }
 
+/*
+ * AMD has indicated that the devices below do not support peer-to-peer
+ * in any system where they are found in the southbridge with an AMD
+ * IOMMU in the system.  Multifunction devices that do not support
+ * peer-to-peer between functions can claim to support a subset of ACS.
+ * Such devices effectively enable request redirect (RR) and completion
+ * redirect (CR) since all transactions are redirected to the upstream
+ * root complex.
+ *
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94086
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94102
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/99402
+ *
+ * 1002:4385 SBx00 SMBus Controller
+ * 1002:439c SB7x0/SB8x0/SB9x0 IDE Controller
+ * 1002:4383 SBx00 Azalia (Intel HDA)
+ * 1002:439d SB7x0/SB8x0/SB9x0 LPC host controller
+ * 1002:4384 SBx00 PCI to PCI Bridge
+ * 1002:4399 SB7x0/SB8x0/SB9x0 USB OHCI2 Controller
+ */
+static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
+{
+#ifdef CONFIG_ACPI
+       struct acpi_table_header *header = NULL;
+       acpi_status status;
+
+       /* Targeting multifunction devices on the SB (appears on root bus) */
+       if (!dev->multifunction || !pci_is_root_bus(dev->bus))
+               return -ENODEV;
+
+       /* The IVRS table describes the AMD IOMMU */
+       status = acpi_get_table("IVRS", 0, &header);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       /* Filter out flags not applicable to multifunction */
+       acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
+
+       return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
+#else
+       return -ENODEV;
+#endif
+}
+
 static const struct pci_dev_acs_enabled {
        u16 vendor;
        u16 device;
        int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
 } pci_dev_acs_enabled[] = {
+       { PCI_VENDOR_ID_ATI, 0x4385, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x439c, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4383, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
        { 0 }
 };
 
index d254e237953382bb99768c7cca79b65c3b9aded8..9be359594b059cf8dffb5241bd9029d38b0d7dfd 100644 (file)
@@ -747,14 +747,14 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
-       unsigned long size = 0, size0 = 0, size1 = 0;
+       resource_size_t size = 0, size0 = 0, size1 = 0;
        resource_size_t children_add_size = 0;
-       resource_size_t min_align, io_align, align;
+       resource_size_t min_align, align;
 
        if (!b_res)
                return;
 
-       io_align = min_align = window_alignment(bus, IORESOURCE_IO);
+       min_align = window_alignment(bus, IORESOURCE_IO);
        list_for_each_entry(dev, &bus->devices, bus_list) {
                int i;
 
@@ -781,9 +781,6 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                }
        }
 
-       if (min_align > io_align)
-               min_align = io_align;
-
        size0 = calculate_iosize(size, min_size, size1,
                        resource_size(b_res), min_align);
        if (children_add_size > add_size)
@@ -807,8 +804,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                add_to_list(realloc_head, bus->self, b_res, size1-size0,
                            min_align);
                dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
-                                "%pR to %pR add_size %lx\n", b_res,
-                                &bus->busn_res, size1-size0);
+                                "%pR to %pR add_size %llx\n", b_res,
+                                &bus->busn_res,
+                                (unsigned long long)size1-size0);
        }
 }
 
@@ -838,6 +836,8 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
  * pbus_size_mem() - size the memory window of a given bus
  *
  * @bus : the bus
+ * @mask: mask the resource flag, then compare it with type
+ * @type: the type of free resource from bridge
  * @min_size : the minimum memory window that must to be allocated
  * @add_size : additional optional memory window
  * @realloc_head : track the additional memory window on this list
@@ -1297,39 +1297,21 @@ static void pci_bus_dump_resources(struct pci_bus *bus)
        }
 }
 
-static int __init pci_bus_get_depth(struct pci_bus *bus)
+static int pci_bus_get_depth(struct pci_bus *bus)
 {
        int depth = 0;
-       struct pci_dev *dev;
+       struct pci_bus *child_bus;
 
-       list_for_each_entry(dev, &bus->devices, bus_list) {
+       list_for_each_entry(child_bus, &bus->children, node){
                int ret;
-               struct pci_bus *b = dev->subordinate;
-               if (!b)
-                       continue;
 
-               ret = pci_bus_get_depth(b);
+               ret = pci_bus_get_depth(child_bus);
                if (ret + 1 > depth)
                        depth = ret + 1;
        }
 
        return depth;
 }
-static int __init pci_get_max_depth(void)
-{
-       int depth = 0;
-       struct pci_bus *bus;
-
-       list_for_each_entry(bus, &pci_root_buses, node) {
-               int ret;
-
-               ret = pci_bus_get_depth(bus);
-               if (ret > depth)
-                       depth = ret;
-       }
-
-       return depth;
-}
 
 /*
  * -1: undefined, will auto detect later
@@ -1346,7 +1328,7 @@ enum enable_type {
        auto_enabled,
 };
 
-static enum enable_type pci_realloc_enable __initdata = undefined;
+static enum enable_type pci_realloc_enable = undefined;
 void __init pci_realloc_get_opt(char *str)
 {
        if (!strncmp(str, "off", 3))
@@ -1354,45 +1336,64 @@ void __init pci_realloc_get_opt(char *str)
        else if (!strncmp(str, "on", 2))
                pci_realloc_enable = user_enabled;
 }
-static bool __init pci_realloc_enabled(void)
+static bool pci_realloc_enabled(enum enable_type enable)
 {
-       return pci_realloc_enable >= user_enabled;
+       return enable >= user_enabled;
 }
 
-static void __init pci_realloc_detect(void)
-{
 #if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO)
-       struct pci_dev *dev = NULL;
-
-       if (pci_realloc_enable != undefined)
-               return;
-
-       for_each_pci_dev(dev) {
-               int i;
+static int iov_resources_unassigned(struct pci_dev *dev, void *data)
+{
+       int i;
+       bool *unassigned = data;
 
-               for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
-                       struct resource *r = &dev->resource[i];
+       for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+               struct resource *r = &dev->resource[i];
+               struct pci_bus_region region;
 
-                       /* Not assigned, or rejected by kernel ? */
-                       if (r->flags && !r->start) {
-                               pci_realloc_enable = auto_enabled;
+               /* Not assigned or rejected by kernel? */
+               if (!r->flags)
+                       continue;
 
-                               return;
-                       }
+               pcibios_resource_to_bus(dev, &region, r);
+               if (!region.start) {
+                       *unassigned = true;
+                       return 1; /* return early from pci_walk_bus() */
                }
        }
-#endif
+
+       return 0;
 }
 
+static enum enable_type pci_realloc_detect(struct pci_bus *bus,
+                        enum enable_type enable_local)
+{
+       bool unassigned = false;
+
+       if (enable_local != undefined)
+               return enable_local;
+
+       pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
+       if (unassigned)
+               return auto_enabled;
+
+       return enable_local;
+}
+#else
+static enum enable_type pci_realloc_detect(struct pci_bus *bus,
+                        enum enable_type enable_local)
+{
+       return enable_local;
+}
+#endif
+
 /*
  * first try will not touch pci bridge res
  * second  and later try will clear small leaf bridge res
  * will stop till to the max  deepth if can not find good one
  */
-void __init
-pci_assign_unassigned_resources(void)
+void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
 {
-       struct pci_bus *bus;
        LIST_HEAD(realloc_head); /* list of resources that
                                        want additional resources */
        struct list_head *add_list = NULL;
@@ -1403,15 +1404,17 @@ pci_assign_unassigned_resources(void)
        unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
                                  IORESOURCE_PREFETCH;
        int pci_try_num = 1;
+       enum enable_type enable_local;
 
        /* don't realloc if asked to do so */
-       pci_realloc_detect();
-       if (pci_realloc_enabled()) {
-               int max_depth = pci_get_max_depth();
+       enable_local = pci_realloc_detect(bus, pci_realloc_enable);
+       if (pci_realloc_enabled(enable_local)) {
+               int max_depth = pci_bus_get_depth(bus);
 
                pci_try_num = max_depth + 1;
-               printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
-                        max_depth, pci_try_num);
+               dev_printk(KERN_DEBUG, &bus->dev,
+                          "max bus depth: %d pci_try_num: %d\n",
+                          max_depth, pci_try_num);
        }
 
 again:
@@ -1423,32 +1426,30 @@ again:
                add_list = &realloc_head;
        /* Depth first, calculate sizes and alignments of all
           subordinate buses. */
-       list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_size_bridges(bus, add_list);
+       __pci_bus_size_bridges(bus, add_list);
 
        /* Depth last, allocate resources and update the hardware. */
-       list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_assign_resources(bus, add_list, &fail_head);
+       __pci_bus_assign_resources(bus, add_list, &fail_head);
        if (add_list)
                BUG_ON(!list_empty(add_list));
        tried_times++;
 
        /* any device complain? */
        if (list_empty(&fail_head))
-               goto enable_and_dump;
+               goto dump;
 
        if (tried_times >= pci_try_num) {
-               if (pci_realloc_enable == undefined)
-                       printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n");
-               else if (pci_realloc_enable == auto_enabled)
-                       printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
+               if (enable_local == undefined)
+                       dev_info(&bus->dev, "Some PCI device resources are unassigned, try booting with pci=realloc\n");
+               else if (enable_local == auto_enabled)
+                       dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
 
                free_list(&fail_head);
-               goto enable_and_dump;
+               goto dump;
        }
 
-       printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
-                        tried_times + 1);
+       dev_printk(KERN_DEBUG, &bus->dev,
+                  "No. %d try to assign unassigned res\n", tried_times + 1);
 
        /* third times and later will not check if it is leaf */
        if ((tried_times + 1) > 2)
@@ -1458,12 +1459,11 @@ again:
         * Try to release leaf bridge's resources that doesn't fit resource of
         * child device under that bridge
         */
-       list_for_each_entry(fail_res, &fail_head, list) {
-               bus = fail_res->dev->bus;
-               pci_bus_release_bridge_resources(bus,
+       list_for_each_entry(fail_res, &fail_head, list)
+               pci_bus_release_bridge_resources(fail_res->dev->bus,
                                                 fail_res->flags & type_mask,
                                                 rel_type);
-       }
+
        /* restore size and flags */
        list_for_each_entry(fail_res, &fail_head, list) {
                struct resource *res = fail_res->res;
@@ -1478,14 +1478,17 @@ again:
 
        goto again;
 
-enable_and_dump:
-       /* Depth last, update the hardware. */
-       list_for_each_entry(bus, &pci_root_buses, node)
-               pci_enable_bridges(bus);
-
+dump:
        /* dump the resource on buses */
-       list_for_each_entry(bus, &pci_root_buses, node)
-               pci_bus_dump_resources(bus);
+       pci_bus_dump_resources(bus);
+}
+
+void __init pci_assign_unassigned_resources(void)
+{
+       struct pci_bus *root_bus;
+
+       list_for_each_entry(root_bus, &pci_root_buses, node)
+               pci_assign_unassigned_root_bus_resources(root_bus);
 }
 
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
@@ -1522,13 +1525,11 @@ again:
         * Try to release leaf bridge's resources that doesn't fit resource of
         * child device under that bridge
         */
-       list_for_each_entry(fail_res, &fail_head, list) {
-               struct pci_bus *bus = fail_res->dev->bus;
-               unsigned long flags = fail_res->flags;
-
-               pci_bus_release_bridge_resources(bus, flags & type_mask,
+       list_for_each_entry(fail_res, &fail_head, list)
+               pci_bus_release_bridge_resources(fail_res->dev->bus,
+                                                fail_res->flags & type_mask,
                                                 whole_subtree);
-       }
+
        /* restore size and flags */
        list_for_each_entry(fail_res, &fail_head, list) {
                struct resource *res = fail_res->res;
@@ -1548,7 +1549,6 @@ enable_all:
        if (retval)
                dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval);
        pci_set_master(bridge);
-       pci_enable_bridges(parent);
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
index 9d3ac998fc1fac6bbfc35efb0ffac398613f6882..b2a98cdbd0d289dee032dfd71cd540ead129b8cc 100644 (file)
@@ -91,7 +91,6 @@ int __ref cb_alloc(struct pcmcia_socket *s)
        if (s->tune_bridge)
                s->tune_bridge(s, bus);
 
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return 0;
index 89ed12379f2fdd63a62e1e1a00f82555dad893ca..186540d74f365fa46c95290a64ad22302b320a7c 100644 (file)
@@ -675,7 +675,7 @@ struct pci_driver {
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
-void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+void pcie_bus_configure_settings(struct pci_bus *bus);
 
 enum pcie_bus_config_types {
        PCIE_BUS_TUNE_OFF,
@@ -914,6 +914,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev);
 void pci_msi_off(struct pci_dev *dev);
 int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
 int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
+int pci_wait_for_pending_transaction(struct pci_dev *dev);
 int pcix_get_max_mmrbc(struct pci_dev *dev);
 int pcix_get_mmrbc(struct pci_dev *dev);
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
@@ -924,6 +925,11 @@ int pcie_set_mps(struct pci_dev *dev, int mps);
 int __pci_reset_function(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
+int pci_probe_reset_slot(struct pci_slot *slot);
+int pci_reset_slot(struct pci_slot *slot);
+int pci_probe_reset_bus(struct pci_bus *bus);
+int pci_reset_bus(struct pci_bus *bus);
+void pci_reset_bridge_secondary_bus(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
@@ -1003,6 +1009,7 @@ int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
+void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
 void pdev_enable_device(struct pci_dev *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
@@ -1043,7 +1050,6 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
                                                  resource_size_t,
                                                  resource_size_t),
                        void *alignf_data);
-void pci_enable_bridges(struct pci_bus *bus);
 
 /* Proper probing supporting hot-pluggable devices */
 int __must_check __pci_register_driver(struct pci_driver *, struct module *,
index 8db71dcd633740a8a7290aff4a99f6a23ee8e366..bd32109e607e9769ac2e972ced22da8650f1fcfe 100644 (file)
@@ -63,6 +63,9 @@ enum pcie_link_width {
  * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
  *     If this field is NULL, the value passed in the struct hotplug_slot_info
  *     will be used when this value is requested by a user.
+ * @reset_slot: Optional interface to allow override of a bus reset for the
+ *     slot for cases where a secondary bus reset can result in spurious
+ *     hotplug events or where a slot can be reset independent of the bus.
  *
  * The table of function pointers that is passed to the hotplug pci core by a
  * hotplug pci driver.  These functions are called by the hotplug pci core when
@@ -80,6 +83,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);
 };
 
 /**