]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Feb 2009 22:43:42 +0000 (14:43 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Feb 2009 22:43:42 +0000 (14:43 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  PCI: AMD 813x B2 devices do not need boot interrupt quirk
  PCI: Enable PCIe AER only after checking firmware support
  PCI: pciehp: Handle interrupts that happen during initialization.
  PCI: don't enable too many HT MSI mappings
  PCI: add some sysfs ABI docs
  PCI quirk: enable MSI on 8132

Documentation/ABI/testing/sysfs-bus-pci
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/quirks.c

index ceddcff4082a0cfc2bdc692148ec455bb9e165f0..e638e15a8895abef445cedccb2df273f1e3ad0e1 100644 (file)
@@ -1,3 +1,46 @@
+What:          /sys/bus/pci/drivers/.../bind
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device location to this file will cause
+               the driver to attempt to bind to the device found at
+               this location.  This is useful for overriding default
+               bindings.  The format for the location is: DDDD:BB:DD.F.
+               That is Domain:Bus:Device.Function and is the same as
+               found in /sys/bus/pci/devices/.  For example:
+               # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind
+               (Note: kernels before 2.6.28 may require echo -n).
+
+What:          /sys/bus/pci/drivers/.../unbind
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device location to this file will cause the
+               driver to attempt to unbind from the device found at
+               this location.  This may be useful when overriding default
+               bindings.  The format for the location is: DDDD:BB:DD.F.
+               That is Domain:Bus:Device.Function and is the same as
+               found in /sys/bus/pci/devices/. For example:
+               # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/unbind
+               (Note: kernels before 2.6.28 may require echo -n).
+
+What:          /sys/bus/pci/drivers/.../new_id
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device ID to this file will attempt to
+               dynamically add a new device ID to a PCI device driver.
+               This may allow the driver to support more hardware than
+               was included in the driver's static device ID support
+               table at compile time.  The format for the device ID is:
+               VVVV DDDD SVVV SDDD CCCC MMMM PPPP.  That is Vendor ID,
+               Device ID, Subsystem Vendor ID, Subsystem Device ID,
+               Class, Class Mask, and Private Driver Data.  The Vendor ID
+               and Device ID fields are required, the rest are optional.
+               Upon successfully adding an ID, the driver will probe
+               for the device and attempt to bind to it.  For example:
+               # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id
+
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
 Contact:       Ben Hutchings <bhutchings@solarflare.com>
index db85284ffb621a98d93252f8c6d6069aa43fb006..39ae37589fda7f6106d845148d1175b4a927b1df 100644 (file)
@@ -111,6 +111,7 @@ struct controller {
        int cmd_busy;
        unsigned int no_cmd_complete:1;
        unsigned int link_active_reporting:1;
+       unsigned int notification_enabled:1;
 };
 
 #define INT_BUTTON_IGNORE              0
@@ -170,6 +171,7 @@ extern int pciehp_configure_device(struct slot *p_slot);
 extern int pciehp_unconfigure_device(struct slot *p_slot);
 extern void pciehp_queue_pushbutton_work(struct work_struct *work);
 struct controller *pcie_init(struct pcie_device *dev);
+int pcie_init_notification(struct controller *ctrl);
 int pciehp_enable_slot(struct slot *p_slot);
 int pciehp_disable_slot(struct slot *p_slot);
 int pcie_enable_notification(struct controller *ctrl);
index c2485542f54356f01c016e83c082e96e3866b62c..681e3912b821a4dce3f5ee11844b73cf6e8b316d 100644 (file)
@@ -434,6 +434,13 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
                goto err_out_release_ctlr;
        }
 
+       /* Enable events after we have setup the data structures */
+       rc = pcie_init_notification(ctrl);
+       if (rc) {
+               ctrl_err(ctrl, "Notification initialization failed\n");
+               goto err_out_release_ctlr;
+       }
+
        /* Check if slot is occupied */
        t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
        t_slot->hpc_ops->get_adapter_status(t_slot, &value);
index 71a8012886b0f0705dcd6cfb27827720ce006cf4..7a16c6897bb92698abc8edfb9af1d909f235453d 100644 (file)
@@ -934,7 +934,7 @@ static void pcie_disable_notification(struct controller *ctrl)
                ctrl_warn(ctrl, "Cannot disable software notification\n");
 }
 
-static int pcie_init_notification(struct controller *ctrl)
+int pcie_init_notification(struct controller *ctrl)
 {
        if (pciehp_request_irq(ctrl))
                return -1;
@@ -942,13 +942,17 @@ static int pcie_init_notification(struct controller *ctrl)
                pciehp_free_irq(ctrl);
                return -1;
        }
+       ctrl->notification_enabled = 1;
        return 0;
 }
 
 static void pcie_shutdown_notification(struct controller *ctrl)
 {
-       pcie_disable_notification(ctrl);
-       pciehp_free_irq(ctrl);
+       if (ctrl->notification_enabled) {
+               pcie_disable_notification(ctrl);
+               pciehp_free_irq(ctrl);
+               ctrl->notification_enabled = 0;
+       }
 }
 
 static int pcie_init_slot(struct controller *ctrl)
@@ -1110,13 +1114,8 @@ struct controller *pcie_init(struct pcie_device *dev)
        if (pcie_init_slot(ctrl))
                goto abort_ctrl;
 
-       if (pcie_init_notification(ctrl))
-               goto abort_slot;
-
        return ctrl;
 
-abort_slot:
-       pcie_cleanup_slot(ctrl);
 abort_ctrl:
        kfree(ctrl);
 abort:
index aac7006949f15c9eb52b56968a4dca6ef812e3c2..d0c9736858689f62f19dc6fd85572dacc3c2d3ec 100644 (file)
@@ -108,6 +108,34 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
 }
 #endif  /*  0  */
 
+
+static void set_device_error_reporting(struct pci_dev *dev, void *data)
+{
+       bool enable = *((bool *)data);
+
+       if (dev->pcie_type != PCIE_RC_PORT &&
+           dev->pcie_type != PCIE_SW_UPSTREAM_PORT &&
+           dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT)
+               return;
+
+       if (enable)
+               pci_enable_pcie_error_reporting(dev);
+       else
+               pci_disable_pcie_error_reporting(dev);
+}
+
+/**
+ * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
+ * @dev: pointer to root port's pci_dev data structure
+ * @enable: true = enable error reporting, false = disable error reporting.
+ */
+static void set_downstream_devices_error_reporting(struct pci_dev *dev,
+                                                  bool enable)
+{
+       set_device_error_reporting(dev, &enable);
+       pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
+}
+
 static int find_device_iter(struct device *device, void *data)
 {
        struct pci_dev *dev;
@@ -525,15 +553,11 @@ void aer_enable_rootport(struct aer_rpc *rpc)
        pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
        pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
 
-       /* Enable Root Port device reporting error itself */
-       pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
-       reg16 = reg16 |
-               PCI_EXP_DEVCTL_CERE |
-               PCI_EXP_DEVCTL_NFERE |
-               PCI_EXP_DEVCTL_FERE |
-               PCI_EXP_DEVCTL_URRE;
-       pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
-               reg16);
+       /*
+        * Enable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, true);
 
        /* Enable Root Port's interrupt in response to error messages */
        pci_write_config_dword(pdev,
@@ -553,6 +577,12 @@ static void disable_root_aer(struct aer_rpc *rpc)
        u32 reg32;
        int pos;
 
+       /*
+        * Disable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, false);
+
        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
        /* Disable Root's interrupt in response to error messages */
        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
index f9b874eaeb9f80daea9f7eff884574cf7f749008..248b4db915526e5819c7050737f4467456aeda9f 100644 (file)
@@ -97,8 +97,6 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
 
        pcie_portdrv_save_config(dev);
 
-       pci_enable_pcie_error_reporting(dev);
-
        return 0;
 }
 
index baad093aafe3c75088c6a1f19d28d826dd5a63de..f20d55368edb7edfb5d0a6bc9ef1a8746da6b8cb 100644 (file)
@@ -1584,6 +1584,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_
  */
 #define AMD_813X_MISC                  0x40
 #define AMD_813X_NOIOAMODE             (1<<0)
+#define AMD_813X_REV_B2                        0x13
 
 static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
 {
@@ -1591,6 +1592,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
 
        if (noioapicquirk)
                return;
+       if (dev->revision == AMD_813X_REV_B2)
+               return;
 
        pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword);
        pci_config_dword &= ~AMD_813X_NOIOAMODE;
@@ -1981,7 +1984,6 @@ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
                        quirk_msi_ht_cap);
 
-
 /* The nVidia CK804 chipset may have 2 HT MSI mappings.
  * MSI are supported if the MSI capability set in any of these mappings.
  */
@@ -2032,6 +2034,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
                         PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
                         ht_enable_msi_mapping);
 
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE,
+                        ht_enable_msi_mapping);
+
 /* The P5N32-SLI Premium motherboard from Asus has a problem with msi
  * for the MCP55 NIC. It is not yet determined whether the msi problem
  * also affects other devices. As for now, turn off msi for this device.
@@ -2048,10 +2053,100 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
-static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
 {
        struct pci_dev *host_bridge;
+       int pos;
+       int i, dev_no;
+       int found = 0;
+
+       dev_no = dev->devfn >> 3;
+       for (i = dev_no; i >= 0; i--) {
+               host_bridge = pci_get_slot(dev->bus, PCI_DEVFN(i, 0));
+               if (!host_bridge)
+                       continue;
+
+               pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
+               if (pos != 0) {
+                       found = 1;
+                       break;
+               }
+               pci_dev_put(host_bridge);
+       }
+
+       if (!found)
+               return;
+
+       /* root did that ! */
+       if (msi_ht_cap_enabled(host_bridge))
+               goto out;
+
+       ht_enable_msi_mapping(dev);
+
+out:
+       pci_dev_put(host_bridge);
+}
+
+static void __devinit ht_disable_msi_mapping(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       dev_info(&dev->dev, "Enabling HT MSI Mapping\n");
+
+                       pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+                                             flags & ~HT_MSI_FLAGS_ENABLE);
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+}
+
+static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
+{
        int pos, ttl = 48;
+       int found = 0;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (found < 1)
+                       found = 1;
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       if (flags & HT_MSI_FLAGS_ENABLE) {
+                               if (found < 2) {
+                                       found = 2;
+                                       break;
+                               }
+                       }
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+
+       return found;
+}
+
+static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+{
+       struct pci_dev *host_bridge;
+       int pos;
+       int found;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       found = ht_check_msi_mapping(dev);
+
+       /* no HT MSI CAP */
+       if (found == 0)
+               return;
 
        /*
         * HT MSI mapping should be disabled on devices that are below
@@ -2067,24 +2162,19 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
        if (pos != 0) {
                /* Host bridge is to HT */
-               ht_enable_msi_mapping(dev);
+               if (found == 1) {
+                       /* it is not enabled, try to enable it */
+                       nv_ht_enable_msi_mapping(dev);
+               }
                return;
        }
 
-       /* Host bridge is not to HT, disable HT MSI mapping on this device */
-       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
-       while (pos && ttl--) {
-               u8 flags;
+       /* HT MSI is not enabled */
+       if (found == 1)
+               return;
 
-               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
-                                        &flags) == 0) {
-                       dev_info(&dev->dev, "Disabling HT MSI mapping");
-                       pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
-                                             flags & ~HT_MSI_FLAGS_ENABLE);
-               }
-               pos = pci_find_next_ht_capability(dev, pos,
-                                                 HT_CAPTYPE_MSI_MAPPING);
-       }
+       /* Host bridge is not to HT, disable HT MSI mapping on this device */
+       ht_disable_msi_mapping(dev);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);