Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* '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
This commit is contained in:
commit
4bdc1b9650
7 changed files with 204 additions and 35 deletions
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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, ®32);
|
||||
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, ®16);
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_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, ttl = 48;
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue