mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 08:26:59 +00:00
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (74 commits) PCI: make msi_free_irqs() to use msix_mask_irq() instead of open coded write PCI: Fix the NIU MSI-X problem in a better way PCI ASPM: remove get_root_port_link PCI ASPM: cleanup pcie_aspm_sanity_check PCI ASPM: remove has_switch field PCI ASPM: cleanup calc_Lx_latency PCI ASPM: cleanup pcie_aspm_get_cap_device PCI ASPM: cleanup clkpm checks PCI ASPM: cleanup __pcie_aspm_check_state_one PCI ASPM: cleanup initialization PCI ASPM: cleanup change input argument of aspm functions PCI ASPM: cleanup misc in struct pcie_link_state PCI ASPM: cleanup clkpm state in struct pcie_link_state PCI ASPM: cleanup latency field in struct pcie_link_state PCI ASPM: cleanup aspm state field in struct pcie_link_state PCI ASPM: fix typo in struct pcie_link_state PCI: drivers/pci/slot.c should depend on CONFIG_SYSFS PCI: remove redundant __msi_set_enable() PCI PM: consistently use type bool for wake enable variable x86/ACPI: Correct maximum allowed _CRS returned resources and warn if exceeded ...
This commit is contained in:
commit
59ef7a83f1
55 changed files with 3031 additions and 2194 deletions
|
@ -122,3 +122,10 @@ Description:
|
||||||
This symbolic link appears when a device is a Virtual Function.
|
This symbolic link appears when a device is a Virtual Function.
|
||||||
The symbolic link points to the PCI device sysfs entry of the
|
The symbolic link points to the PCI device sysfs entry of the
|
||||||
Physical Function this device associates with.
|
Physical Function this device associates with.
|
||||||
|
|
||||||
|
What: /sys/bus/pci/slots/.../module
|
||||||
|
Date: June 2009
|
||||||
|
Contact: linux-pci@vger.kernel.org
|
||||||
|
Description:
|
||||||
|
This symbolic link points to the PCI hotplug controller driver
|
||||||
|
module that manages the hotplug slot.
|
||||||
|
|
|
@ -61,6 +61,10 @@ be initiated although firmwares have no _OSC support. To enable the
|
||||||
walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
|
walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
|
||||||
when booting kernel. Note that forceload=n by default.
|
when booting kernel. Note that forceload=n by default.
|
||||||
|
|
||||||
|
nosourceid, another parameter of type bool, can be used when broken
|
||||||
|
hardware (mostly chipsets) has root ports that cannot obtain the reporting
|
||||||
|
source ID. nosourceid=n by default.
|
||||||
|
|
||||||
2.3 AER error output
|
2.3 AER error output
|
||||||
When a PCI-E AER error is captured, an error message will be outputed to
|
When a PCI-E AER error is captured, an error message will be outputed to
|
||||||
console. If it's a correctable error, it is outputed as a warning.
|
console. If it's a correctable error, it is outputed as a warning.
|
||||||
|
@ -246,3 +250,24 @@ with the PCI Express AER Root driver?
|
||||||
A: It could call the helper functions to enable AER in devices and
|
A: It could call the helper functions to enable AER in devices and
|
||||||
cleanup uncorrectable status register. Pls. refer to section 3.3.
|
cleanup uncorrectable status register. Pls. refer to section 3.3.
|
||||||
|
|
||||||
|
|
||||||
|
4. Software error injection
|
||||||
|
|
||||||
|
Debugging PCIE AER error recovery code is quite difficult because it
|
||||||
|
is hard to trigger real hardware errors. Software based error
|
||||||
|
injection can be used to fake various kinds of PCIE errors.
|
||||||
|
|
||||||
|
First you should enable PCIE AER software error injection in kernel
|
||||||
|
configuration, that is, following item should be in your .config.
|
||||||
|
|
||||||
|
CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m
|
||||||
|
|
||||||
|
After reboot with new kernel or insert the module, a device file named
|
||||||
|
/dev/aer_inject should be created.
|
||||||
|
|
||||||
|
Then, you need a user space tool named aer-inject, which can be gotten
|
||||||
|
from:
|
||||||
|
http://www.kernel.org/pub/linux/utils/pci/aer-inject/
|
||||||
|
|
||||||
|
More information about aer-inject can be found in the document comes
|
||||||
|
with its source code.
|
||||||
|
|
|
@ -1776,6 +1776,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
root domains (aka PCI segments, in ACPI-speak).
|
root domains (aka PCI segments, in ACPI-speak).
|
||||||
nommconf [X86] Disable use of MMCONFIG for PCI
|
nommconf [X86] Disable use of MMCONFIG for PCI
|
||||||
Configuration
|
Configuration
|
||||||
|
check_enable_amd_mmconf [X86] check for and enable
|
||||||
|
properly configured MMIO access to PCI
|
||||||
|
config space on AMD family 10h CPU
|
||||||
nomsi [MSI] If the PCI_MSI kernel config parameter is
|
nomsi [MSI] If the PCI_MSI kernel config parameter is
|
||||||
enabled, this kernel boot option can be used to
|
enabled, this kernel boot option can be used to
|
||||||
disable the use of MSI interrupts system-wide.
|
disable the use of MSI interrupts system-wide.
|
||||||
|
@ -1828,7 +1831,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
IRQ routing is enabled.
|
IRQ routing is enabled.
|
||||||
noacpi [X86] Do not use ACPI for IRQ routing
|
noacpi [X86] Do not use ACPI for IRQ routing
|
||||||
or for PCI scanning.
|
or for PCI scanning.
|
||||||
use_crs [X86] Use _CRS for PCI resource
|
nocrs [X86] Don't use _CRS for PCI resource
|
||||||
allocation.
|
allocation.
|
||||||
routeirq Do IRQ routing for all PCI devices.
|
routeirq Do IRQ routing for all PCI devices.
|
||||||
This is normally done in pci_enable_device(),
|
This is normally done in pci_enable_device(),
|
||||||
|
@ -1865,6 +1868,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
PAGE_SIZE is used as alignment.
|
PAGE_SIZE is used as alignment.
|
||||||
PCI-PCI bridge can be specified, if resource
|
PCI-PCI bridge can be specified, if resource
|
||||||
windows need to be expanded.
|
windows need to be expanded.
|
||||||
|
ecrc= Enable/disable PCIe ECRC (transaction layer
|
||||||
|
end-to-end CRC checking).
|
||||||
|
bios: Use BIOS/firmware settings. This is the
|
||||||
|
the default.
|
||||||
|
off: Turn ECRC off
|
||||||
|
on: Turn ECRC on.
|
||||||
|
|
||||||
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
|
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
|
||||||
Management.
|
Management.
|
||||||
|
|
|
@ -122,7 +122,7 @@ static void eeh_enable_irq(struct pci_dev *dev)
|
||||||
* passed back in "userdata".
|
* passed back in "userdata".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void eeh_report_error(struct pci_dev *dev, void *userdata)
|
static int eeh_report_error(struct pci_dev *dev, void *userdata)
|
||||||
{
|
{
|
||||||
enum pci_ers_result rc, *res = userdata;
|
enum pci_ers_result rc, *res = userdata;
|
||||||
struct pci_driver *driver = dev->driver;
|
struct pci_driver *driver = dev->driver;
|
||||||
|
@ -130,19 +130,21 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
|
||||||
dev->error_state = pci_channel_io_frozen;
|
dev->error_state = pci_channel_io_frozen;
|
||||||
|
|
||||||
if (!driver)
|
if (!driver)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
eeh_disable_irq(dev);
|
eeh_disable_irq(dev);
|
||||||
|
|
||||||
if (!driver->err_handler ||
|
if (!driver->err_handler ||
|
||||||
!driver->err_handler->error_detected)
|
!driver->err_handler->error_detected)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
|
rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
|
||||||
|
|
||||||
/* A driver that needs a reset trumps all others */
|
/* A driver that needs a reset trumps all others */
|
||||||
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||||||
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,7 +155,7 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
|
||||||
* Cumulative response passed back in "userdata".
|
* Cumulative response passed back in "userdata".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
||||||
{
|
{
|
||||||
enum pci_ers_result rc, *res = userdata;
|
enum pci_ers_result rc, *res = userdata;
|
||||||
struct pci_driver *driver = dev->driver;
|
struct pci_driver *driver = dev->driver;
|
||||||
|
@ -161,26 +163,28 @@ static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
||||||
if (!driver ||
|
if (!driver ||
|
||||||
!driver->err_handler ||
|
!driver->err_handler ||
|
||||||
!driver->err_handler->mmio_enabled)
|
!driver->err_handler->mmio_enabled)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
rc = driver->err_handler->mmio_enabled (dev);
|
rc = driver->err_handler->mmio_enabled (dev);
|
||||||
|
|
||||||
/* A driver that needs a reset trumps all others */
|
/* A driver that needs a reset trumps all others */
|
||||||
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||||||
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* eeh_report_reset - tell device that slot has been reset
|
* eeh_report_reset - tell device that slot has been reset
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void eeh_report_reset(struct pci_dev *dev, void *userdata)
|
static int eeh_report_reset(struct pci_dev *dev, void *userdata)
|
||||||
{
|
{
|
||||||
enum pci_ers_result rc, *res = userdata;
|
enum pci_ers_result rc, *res = userdata;
|
||||||
struct pci_driver *driver = dev->driver;
|
struct pci_driver *driver = dev->driver;
|
||||||
|
|
||||||
if (!driver)
|
if (!driver)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
dev->error_state = pci_channel_io_normal;
|
dev->error_state = pci_channel_io_normal;
|
||||||
|
|
||||||
|
@ -188,35 +192,39 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
|
||||||
|
|
||||||
if (!driver->err_handler ||
|
if (!driver->err_handler ||
|
||||||
!driver->err_handler->slot_reset)
|
!driver->err_handler->slot_reset)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
rc = driver->err_handler->slot_reset(dev);
|
rc = driver->err_handler->slot_reset(dev);
|
||||||
if ((*res == PCI_ERS_RESULT_NONE) ||
|
if ((*res == PCI_ERS_RESULT_NONE) ||
|
||||||
(*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
|
(*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
|
||||||
if (*res == PCI_ERS_RESULT_DISCONNECT &&
|
if (*res == PCI_ERS_RESULT_DISCONNECT &&
|
||||||
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* eeh_report_resume - tell device to resume normal operations
|
* eeh_report_resume - tell device to resume normal operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void eeh_report_resume(struct pci_dev *dev, void *userdata)
|
static int eeh_report_resume(struct pci_dev *dev, void *userdata)
|
||||||
{
|
{
|
||||||
struct pci_driver *driver = dev->driver;
|
struct pci_driver *driver = dev->driver;
|
||||||
|
|
||||||
dev->error_state = pci_channel_io_normal;
|
dev->error_state = pci_channel_io_normal;
|
||||||
|
|
||||||
if (!driver)
|
if (!driver)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
eeh_enable_irq(dev);
|
eeh_enable_irq(dev);
|
||||||
|
|
||||||
if (!driver->err_handler ||
|
if (!driver->err_handler ||
|
||||||
!driver->err_handler->resume)
|
!driver->err_handler->resume)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
driver->err_handler->resume(dev);
|
driver->err_handler->resume(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,22 +234,24 @@ static void eeh_report_resume(struct pci_dev *dev, void *userdata)
|
||||||
* dead, and that no further recovery attempts will be made on it.
|
* dead, and that no further recovery attempts will be made on it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void eeh_report_failure(struct pci_dev *dev, void *userdata)
|
static int eeh_report_failure(struct pci_dev *dev, void *userdata)
|
||||||
{
|
{
|
||||||
struct pci_driver *driver = dev->driver;
|
struct pci_driver *driver = dev->driver;
|
||||||
|
|
||||||
dev->error_state = pci_channel_io_perm_failure;
|
dev->error_state = pci_channel_io_perm_failure;
|
||||||
|
|
||||||
if (!driver)
|
if (!driver)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
eeh_disable_irq(dev);
|
eeh_disable_irq(dev);
|
||||||
|
|
||||||
if (!driver->err_handler ||
|
if (!driver->err_handler ||
|
||||||
!driver->err_handler->error_detected)
|
!driver->err_handler->error_detected)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
|
driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------- */
|
/* ------------------------------------------------------- */
|
||||||
|
|
|
@ -130,6 +130,7 @@ extern void pci_iommu_alloc(void);
|
||||||
|
|
||||||
/* generic pci stuff */
|
/* generic pci stuff */
|
||||||
#include <asm-generic/pci.h>
|
#include <asm-generic/pci.h>
|
||||||
|
#define PCIBIOS_MAX_MEM_32 0xffffffff
|
||||||
|
|
||||||
#ifdef CONFIG_NUMA
|
#ifdef CONFIG_NUMA
|
||||||
/* Returns the node based on pci bus */
|
/* Returns the node based on pci bus */
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define PCI_BIOS_IRQ_SCAN 0x2000
|
#define PCI_BIOS_IRQ_SCAN 0x2000
|
||||||
#define PCI_ASSIGN_ALL_BUSSES 0x4000
|
#define PCI_ASSIGN_ALL_BUSSES 0x4000
|
||||||
#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
|
#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
|
||||||
#define PCI_USE__CRS 0x10000
|
#define PCI_NO_ROOT_CRS 0x10000
|
||||||
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
|
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
|
||||||
#define PCI_HAS_IO_ECS 0x40000
|
#define PCI_HAS_IO_ECS 0x40000
|
||||||
#define PCI_NOASSIGN_ROMS 0x80000
|
#define PCI_NOASSIGN_ROMS 0x80000
|
||||||
|
|
|
@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data)
|
||||||
struct acpi_resource_address64 addr;
|
struct acpi_resource_address64 addr;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
|
|
||||||
return AE_OK;
|
|
||||||
|
|
||||||
status = resource_to_addr(acpi_res, &addr);
|
status = resource_to_addr(acpi_res, &addr);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
info->res_num++;
|
info->res_num++;
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bus_has_transparent_bridge(struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
struct pci_dev *dev;
|
||||||
|
|
||||||
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||||
|
u16 class = dev->class >> 8;
|
||||||
|
|
||||||
|
if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static acpi_status
|
static acpi_status
|
||||||
setup_resource(struct acpi_resource *acpi_res, void *data)
|
setup_resource(struct acpi_resource *acpi_res, void *data)
|
||||||
{
|
{
|
||||||
|
@ -56,9 +67,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct resource *root;
|
struct resource *root;
|
||||||
|
int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
|
||||||
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
|
|
||||||
return AE_OK;
|
|
||||||
|
|
||||||
status = resource_to_addr(acpi_res, &addr);
|
status = resource_to_addr(acpi_res, &addr);
|
||||||
if (!ACPI_SUCCESS(status))
|
if (!ACPI_SUCCESS(status))
|
||||||
|
@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
|
||||||
res->end = res->start + addr.address_length - 1;
|
res->end = res->start + addr.address_length - 1;
|
||||||
res->child = NULL;
|
res->child = NULL;
|
||||||
|
|
||||||
|
if (bus_has_transparent_bridge(info->bus))
|
||||||
|
max_root_bus_resources -= 3;
|
||||||
|
if (info->res_num >= max_root_bus_resources) {
|
||||||
|
printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx "
|
||||||
|
"from %s for %s due to _CRS returning more than "
|
||||||
|
"%d resource descriptors\n", (unsigned long) res->start,
|
||||||
|
(unsigned long) res->end, root->name, info->name,
|
||||||
|
max_root_bus_resources);
|
||||||
|
info->res_num++;
|
||||||
|
return AE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (insert_resource(root, res)) {
|
if (insert_resource(root, res)) {
|
||||||
printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
|
printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
|
||||||
"from %s for %s\n", (unsigned long) res->start,
|
"from %s for %s\n", (unsigned long) res->start,
|
||||||
|
@ -217,7 +238,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bus && (pci_probe & PCI_USE__CRS))
|
if (bus && !(pci_probe & PCI_NO_ROOT_CRS))
|
||||||
get_current_resources(device, busnum, domain, bus);
|
get_current_resources(device, busnum, domain, bus);
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
|
||||||
struct pci_root_info *info;
|
struct pci_root_info *info;
|
||||||
|
|
||||||
/* don't go for it if _CRS is used */
|
/* don't go for it if _CRS is used */
|
||||||
if (pci_probe & PCI_USE__CRS)
|
if (!(pci_probe & PCI_NO_ROOT_CRS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* if only one root bus, don't need to anything */
|
/* if only one root bus, don't need to anything */
|
||||||
|
|
|
@ -515,8 +515,8 @@ char * __devinit pcibios_setup(char *str)
|
||||||
} else if (!strcmp(str, "assign-busses")) {
|
} else if (!strcmp(str, "assign-busses")) {
|
||||||
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
|
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (!strcmp(str, "use_crs")) {
|
} else if (!strcmp(str, "nocrs")) {
|
||||||
pci_probe |= PCI_USE__CRS;
|
pci_probe |= PCI_NO_ROOT_CRS;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (!strcmp(str, "earlydump")) {
|
} else if (!strcmp(str, "earlydump")) {
|
||||||
pci_early_dump_regs = 1;
|
pci_early_dump_regs = 1;
|
||||||
|
|
|
@ -266,6 +266,7 @@ config ACPI_DEBUG_FUNC_TRACE
|
||||||
|
|
||||||
config ACPI_PCI_SLOT
|
config ACPI_PCI_SLOT
|
||||||
tristate "PCI slot detection driver"
|
tristate "PCI slot detection driver"
|
||||||
|
depends on SYSFS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
This driver creates entries in /sys/bus/pci/slots/ for all PCI
|
This driver creates entries in /sys/bus/pci/slots/ for all PCI
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
# Makefile for the PCI bus specific drivers.
|
# Makefile for the PCI bus specific drivers.
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \
|
obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
|
||||||
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
|
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
|
||||||
irq.o
|
irq.o
|
||||||
obj-$(CONFIG_PROC_FS) += proc.o
|
obj-$(CONFIG_PROC_FS) += proc.o
|
||||||
|
obj-$(CONFIG_SYSFS) += slot.o
|
||||||
|
|
||||||
# Build PCI Express stuff if needed
|
# Build PCI Express stuff if needed
|
||||||
obj-$(CONFIG_PCIEPORTBUS) += pcie/
|
obj-$(CONFIG_PCIEPORTBUS) += pcie/
|
||||||
|
|
|
@ -66,6 +66,25 @@ EXPORT_SYMBOL(pci_bus_write_config_byte);
|
||||||
EXPORT_SYMBOL(pci_bus_write_config_word);
|
EXPORT_SYMBOL(pci_bus_write_config_word);
|
||||||
EXPORT_SYMBOL(pci_bus_write_config_dword);
|
EXPORT_SYMBOL(pci_bus_write_config_dword);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_bus_set_ops - Set raw operations of pci bus
|
||||||
|
* @bus: pci bus struct
|
||||||
|
* @ops: new raw operations
|
||||||
|
*
|
||||||
|
* Return previous raw operations
|
||||||
|
*/
|
||||||
|
struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
|
||||||
|
{
|
||||||
|
struct pci_ops *old_ops;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&pci_lock, flags);
|
||||||
|
old_ops = bus->ops;
|
||||||
|
bus->ops = ops;
|
||||||
|
spin_unlock_irqrestore(&pci_lock, flags);
|
||||||
|
return old_ops;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pci_bus_set_ops);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_read_vpd - Read one entry from Vital Product Data
|
* pci_read_vpd - Read one entry from Vital Product Data
|
||||||
|
|
|
@ -41,9 +41,14 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
|
||||||
void *alignf_data)
|
void *alignf_data)
|
||||||
{
|
{
|
||||||
int i, ret = -ENOMEM;
|
int i, ret = -ENOMEM;
|
||||||
|
resource_size_t max = -1;
|
||||||
|
|
||||||
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
|
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
|
||||||
|
|
||||||
|
/* don't allocate too high if the pref mem doesn't support 64bit*/
|
||||||
|
if (!(res->flags & IORESOURCE_MEM_64))
|
||||||
|
max = PCIBIOS_MAX_MEM_32;
|
||||||
|
|
||||||
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
|
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
|
||||||
struct resource *r = bus->resource[i];
|
struct resource *r = bus->resource[i];
|
||||||
if (!r)
|
if (!r)
|
||||||
|
@ -62,7 +67,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
|
||||||
/* Ok, try it out.. */
|
/* Ok, try it out.. */
|
||||||
ret = allocate_resource(r, res, size,
|
ret = allocate_resource(r, res, size,
|
||||||
r->start ? : min,
|
r->start ? : min,
|
||||||
-1, align,
|
max, align,
|
||||||
alignf, alignf_data);
|
alignf, alignf_data);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -201,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus)
|
||||||
* Walk the given bus, including any bridged devices
|
* Walk the given bus, including any bridged devices
|
||||||
* on buses under this bus. Call the provided callback
|
* on buses under this bus. Call the provided callback
|
||||||
* on each device found.
|
* on each device found.
|
||||||
|
*
|
||||||
|
* We check the return of @cb each time. If it returns anything
|
||||||
|
* other than 0, we break out.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
|
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus;
|
struct pci_bus *bus;
|
||||||
struct list_head *next;
|
struct list_head *next;
|
||||||
|
int retval;
|
||||||
|
|
||||||
bus = top;
|
bus = top;
|
||||||
down_read(&pci_bus_sem);
|
down_read(&pci_bus_sem);
|
||||||
|
@ -231,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
|
||||||
|
|
||||||
/* Run device routines with the device locked */
|
/* Run device routines with the device locked */
|
||||||
down(&dev->dev.sem);
|
down(&dev->dev.sem);
|
||||||
cb(dev, userdata);
|
retval = cb(dev, userdata);
|
||||||
up(&dev->dev.sem);
|
up(&dev->dev.sem);
|
||||||
|
if (retval)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
up_read(&pci_bus_sem);
|
up_read(&pci_bus_sem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
menuconfig HOTPLUG_PCI
|
menuconfig HOTPLUG_PCI
|
||||||
tristate "Support for PCI Hotplug"
|
tristate "Support for PCI Hotplug"
|
||||||
depends on PCI && HOTPLUG
|
depends on PCI && HOTPLUG && SYSFS
|
||||||
---help---
|
---help---
|
||||||
Say Y here if you have a motherboard with a PCI Hotplug controller.
|
Say Y here if you have a motherboard with a PCI Hotplug controller.
|
||||||
This allows you to add and remove PCI cards while the machine is
|
This allows you to add and remove PCI cards while the machine is
|
||||||
|
@ -41,7 +41,7 @@ config HOTPLUG_PCI_FAKE
|
||||||
|
|
||||||
config HOTPLUG_PCI_COMPAQ
|
config HOTPLUG_PCI_COMPAQ
|
||||||
tristate "Compaq PCI Hotplug driver"
|
tristate "Compaq PCI Hotplug driver"
|
||||||
depends on X86 && PCI_BIOS && PCI_LEGACY
|
depends on X86 && PCI_BIOS
|
||||||
help
|
help
|
||||||
Say Y here if you have a motherboard with a Compaq PCI Hotplug
|
Say Y here if you have a motherboard with a Compaq PCI Hotplug
|
||||||
controller.
|
controller.
|
||||||
|
|
|
@ -77,7 +77,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value);
|
||||||
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
|
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
|
static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
|
|
|
@ -72,7 +72,6 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
|
||||||
static int get_latch_status(struct hotplug_slot *slot, u8 * value);
|
static int get_latch_status(struct hotplug_slot *slot, u8 * value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
|
static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
|
|
|
@ -150,25 +150,25 @@ struct ctrl_reg { /* offset */
|
||||||
|
|
||||||
/* offsets to the controller registers based on the above structure layout */
|
/* offsets to the controller registers based on the above structure layout */
|
||||||
enum ctrl_offsets {
|
enum ctrl_offsets {
|
||||||
SLOT_RST = offsetof(struct ctrl_reg, slot_RST),
|
SLOT_RST = offsetof(struct ctrl_reg, slot_RST),
|
||||||
SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable),
|
SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable),
|
||||||
MISC = offsetof(struct ctrl_reg, misc),
|
MISC = offsetof(struct ctrl_reg, misc),
|
||||||
LED_CONTROL = offsetof(struct ctrl_reg, led_control),
|
LED_CONTROL = offsetof(struct ctrl_reg, led_control),
|
||||||
INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear),
|
INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear),
|
||||||
INT_MASK = offsetof(struct ctrl_reg, int_mask),
|
INT_MASK = offsetof(struct ctrl_reg, int_mask),
|
||||||
CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0),
|
CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0),
|
||||||
CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1),
|
CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1),
|
||||||
CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1),
|
CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1),
|
||||||
GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB),
|
GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB),
|
||||||
NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input),
|
NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input),
|
||||||
CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3),
|
CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3),
|
||||||
CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4),
|
CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4),
|
||||||
CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5),
|
CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5),
|
||||||
CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6),
|
CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6),
|
||||||
CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7),
|
CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7),
|
||||||
CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8),
|
CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8),
|
||||||
SLOT_MASK = offsetof(struct ctrl_reg, slot_mask),
|
SLOT_MASK = offsetof(struct ctrl_reg, slot_mask),
|
||||||
CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9),
|
CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9),
|
||||||
CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10),
|
CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10),
|
||||||
CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11),
|
CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11),
|
||||||
SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR),
|
SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR),
|
||||||
|
@ -190,7 +190,9 @@ struct hrt {
|
||||||
u32 reserved2;
|
u32 reserved2;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* offsets to the hotplug resource table registers based on the above structure layout */
|
/* offsets to the hotplug resource table registers based on the above
|
||||||
|
* structure layout
|
||||||
|
*/
|
||||||
enum hrt_offsets {
|
enum hrt_offsets {
|
||||||
SIG0 = offsetof(struct hrt, sig0),
|
SIG0 = offsetof(struct hrt, sig0),
|
||||||
SIG1 = offsetof(struct hrt, sig1),
|
SIG1 = offsetof(struct hrt, sig1),
|
||||||
|
@ -217,18 +219,20 @@ struct slot_rt {
|
||||||
u16 pre_mem_length;
|
u16 pre_mem_length;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* offsets to the hotplug slot resource table registers based on the above structure layout */
|
/* offsets to the hotplug slot resource table registers based on the above
|
||||||
|
* structure layout
|
||||||
|
*/
|
||||||
enum slot_rt_offsets {
|
enum slot_rt_offsets {
|
||||||
DEV_FUNC = offsetof(struct slot_rt, dev_func),
|
DEV_FUNC = offsetof(struct slot_rt, dev_func),
|
||||||
PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
|
PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
|
||||||
SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
|
SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
|
||||||
MAX_BUS = offsetof(struct slot_rt, max_bus),
|
MAX_BUS = offsetof(struct slot_rt, max_bus),
|
||||||
IO_BASE = offsetof(struct slot_rt, io_base),
|
IO_BASE = offsetof(struct slot_rt, io_base),
|
||||||
IO_LENGTH = offsetof(struct slot_rt, io_length),
|
IO_LENGTH = offsetof(struct slot_rt, io_length),
|
||||||
MEM_BASE = offsetof(struct slot_rt, mem_base),
|
MEM_BASE = offsetof(struct slot_rt, mem_base),
|
||||||
MEM_LENGTH = offsetof(struct slot_rt, mem_length),
|
MEM_LENGTH = offsetof(struct slot_rt, mem_length),
|
||||||
PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
|
PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
|
||||||
PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
|
PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pci_func {
|
struct pci_func {
|
||||||
|
@ -286,8 +290,8 @@ struct event_info {
|
||||||
struct controller {
|
struct controller {
|
||||||
struct controller *next;
|
struct controller *next;
|
||||||
u32 ctrl_int_comp;
|
u32 ctrl_int_comp;
|
||||||
struct mutex crit_sect; /* critical section mutex */
|
struct mutex crit_sect; /* critical section mutex */
|
||||||
void __iomem *hpc_reg; /* cookie for our pci controller location */
|
void __iomem *hpc_reg; /* cookie for our pci controller location */
|
||||||
struct pci_resource *mem_head;
|
struct pci_resource *mem_head;
|
||||||
struct pci_resource *p_mem_head;
|
struct pci_resource *p_mem_head;
|
||||||
struct pci_resource *io_head;
|
struct pci_resource *io_head;
|
||||||
|
@ -299,7 +303,7 @@ struct controller {
|
||||||
u8 next_event;
|
u8 next_event;
|
||||||
u8 interrupt;
|
u8 interrupt;
|
||||||
u8 cfgspc_irq;
|
u8 cfgspc_irq;
|
||||||
u8 bus; /* bus number for the pci hotplug controller */
|
u8 bus; /* bus number for the pci hotplug controller */
|
||||||
u8 rev;
|
u8 rev;
|
||||||
u8 slot_device_offset;
|
u8 slot_device_offset;
|
||||||
u8 first_slot;
|
u8 first_slot;
|
||||||
|
@ -401,46 +405,57 @@ struct resource_lists {
|
||||||
|
|
||||||
|
|
||||||
/* debugfs functions for the hotplug controller info */
|
/* debugfs functions for the hotplug controller info */
|
||||||
extern void cpqhp_initialize_debugfs (void);
|
extern void cpqhp_initialize_debugfs(void);
|
||||||
extern void cpqhp_shutdown_debugfs (void);
|
extern void cpqhp_shutdown_debugfs(void);
|
||||||
extern void cpqhp_create_debugfs_files (struct controller *ctrl);
|
extern void cpqhp_create_debugfs_files(struct controller *ctrl);
|
||||||
extern void cpqhp_remove_debugfs_files (struct controller *ctrl);
|
extern void cpqhp_remove_debugfs_files(struct controller *ctrl);
|
||||||
|
|
||||||
/* controller functions */
|
/* controller functions */
|
||||||
extern void cpqhp_pushbutton_thread (unsigned long event_pointer);
|
extern void cpqhp_pushbutton_thread(unsigned long event_pointer);
|
||||||
extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data);
|
extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
|
||||||
extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start);
|
extern int cpqhp_find_available_resources(struct controller *ctrl,
|
||||||
extern int cpqhp_event_start_thread (void);
|
void __iomem *rom_start);
|
||||||
extern void cpqhp_event_stop_thread (void);
|
extern int cpqhp_event_start_thread(void);
|
||||||
extern struct pci_func *cpqhp_slot_create (unsigned char busnumber);
|
extern void cpqhp_event_stop_thread(void);
|
||||||
extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index);
|
extern struct pci_func *cpqhp_slot_create(unsigned char busnumber);
|
||||||
extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func);
|
extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
|
||||||
extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func);
|
unsigned char index);
|
||||||
extern int cpqhp_hardware_test (struct controller *ctrl, int test_num);
|
extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func);
|
||||||
|
extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func);
|
||||||
|
extern int cpqhp_hardware_test(struct controller *ctrl, int test_num);
|
||||||
|
|
||||||
/* resource functions */
|
/* resource functions */
|
||||||
extern int cpqhp_resource_sort_and_combine (struct pci_resource **head);
|
extern int cpqhp_resource_sort_and_combine (struct pci_resource **head);
|
||||||
|
|
||||||
/* pci functions */
|
/* pci functions */
|
||||||
extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
|
extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
|
||||||
extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot);
|
extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num,
|
||||||
extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug);
|
u8 slot);
|
||||||
extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func);
|
extern int cpqhp_save_config(struct controller *ctrl, int busnumber,
|
||||||
extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func);
|
int is_hot_plug);
|
||||||
extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func);
|
extern int cpqhp_save_base_addr_length(struct controller *ctrl,
|
||||||
extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot);
|
struct pci_func *func);
|
||||||
extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func);
|
extern int cpqhp_save_used_resources(struct controller *ctrl,
|
||||||
extern void cpqhp_destroy_board_resources (struct pci_func * func);
|
struct pci_func *func);
|
||||||
extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources);
|
extern int cpqhp_configure_board(struct controller *ctrl,
|
||||||
extern void cpqhp_destroy_resource_list (struct resource_lists * resources);
|
struct pci_func *func);
|
||||||
extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func);
|
extern int cpqhp_save_slot_config(struct controller *ctrl,
|
||||||
extern int cpqhp_unconfigure_device (struct pci_func* func);
|
struct pci_func *new_slot);
|
||||||
|
extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func);
|
||||||
|
extern void cpqhp_destroy_board_resources(struct pci_func *func);
|
||||||
|
extern int cpqhp_return_board_resources (struct pci_func *func,
|
||||||
|
struct resource_lists *resources);
|
||||||
|
extern void cpqhp_destroy_resource_list(struct resource_lists *resources);
|
||||||
|
extern int cpqhp_configure_device(struct controller *ctrl,
|
||||||
|
struct pci_func *func);
|
||||||
|
extern int cpqhp_unconfigure_device(struct pci_func *func);
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
extern int cpqhp_debug;
|
extern int cpqhp_debug;
|
||||||
extern int cpqhp_legacy_mode;
|
extern int cpqhp_legacy_mode;
|
||||||
extern struct controller *cpqhp_ctrl_list;
|
extern struct controller *cpqhp_ctrl_list;
|
||||||
extern struct pci_func *cpqhp_slot_list[256];
|
extern struct pci_func *cpqhp_slot_list[256];
|
||||||
|
extern struct irq_routing_table *cpqhp_routing_table;
|
||||||
|
|
||||||
/* these can be gotten rid of, but for debugging they are purty */
|
/* these can be gotten rid of, but for debugging they are purty */
|
||||||
extern u8 cpqhp_nic_irq;
|
extern u8 cpqhp_nic_irq;
|
||||||
|
@ -449,7 +464,7 @@ extern u8 cpqhp_disk_irq;
|
||||||
|
|
||||||
/* inline functions */
|
/* inline functions */
|
||||||
|
|
||||||
static inline char *slot_name(struct slot *slot)
|
static inline const char *slot_name(struct slot *slot)
|
||||||
{
|
{
|
||||||
return hotplug_slot_name(slot->hotplug_slot);
|
return hotplug_slot_name(slot->hotplug_slot);
|
||||||
}
|
}
|
||||||
|
@ -458,9 +473,9 @@ static inline char *slot_name(struct slot *slot)
|
||||||
* return_resource
|
* return_resource
|
||||||
*
|
*
|
||||||
* Puts node back in the resource list pointed to by head
|
* Puts node back in the resource list pointed to by head
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
|
static inline void return_resource(struct pci_resource **head,
|
||||||
|
struct pci_resource *node)
|
||||||
{
|
{
|
||||||
if (!node || !head)
|
if (!node || !head)
|
||||||
return;
|
return;
|
||||||
|
@ -575,18 +590,17 @@ static inline u8 read_slot_enable(struct controller *ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* get_controller_speed - find the current frequency/mode of controller.
|
* get_controller_speed - find the current frequency/mode of controller.
|
||||||
*
|
*
|
||||||
* @ctrl: controller to get frequency/mode for.
|
* @ctrl: controller to get frequency/mode for.
|
||||||
*
|
*
|
||||||
* Returns controller speed.
|
* Returns controller speed.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static inline u8 get_controller_speed(struct controller *ctrl)
|
static inline u8 get_controller_speed(struct controller *ctrl)
|
||||||
{
|
{
|
||||||
u8 curr_freq;
|
u8 curr_freq;
|
||||||
u16 misc;
|
u16 misc;
|
||||||
|
|
||||||
if (ctrl->pcix_support) {
|
if (ctrl->pcix_support) {
|
||||||
curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
|
curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
|
||||||
|
@ -602,19 +616,18 @@ static inline u8 get_controller_speed(struct controller *ctrl)
|
||||||
return PCI_SPEED_33MHz;
|
return PCI_SPEED_33MHz;
|
||||||
}
|
}
|
||||||
|
|
||||||
misc = readw(ctrl->hpc_reg + MISC);
|
misc = readw(ctrl->hpc_reg + MISC);
|
||||||
return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
|
return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* get_adapter_speed - find the max supported frequency/mode of adapter.
|
* get_adapter_speed - find the max supported frequency/mode of adapter.
|
||||||
*
|
*
|
||||||
* @ctrl: hotplug controller.
|
* @ctrl: hotplug controller.
|
||||||
* @hp_slot: hotplug slot where adapter is installed.
|
* @hp_slot: hotplug slot where adapter is installed.
|
||||||
*
|
*
|
||||||
* Returns adapter speed.
|
* Returns adapter speed.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot)
|
static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot)
|
||||||
{
|
{
|
||||||
|
@ -672,7 +685,8 @@ static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot)
|
static inline int cpq_get_latch_status(struct controller *ctrl,
|
||||||
|
struct slot *slot)
|
||||||
{
|
{
|
||||||
u32 status;
|
u32 status;
|
||||||
u8 hp_slot;
|
u8 hp_slot;
|
||||||
|
@ -687,7 +701,8 @@ static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int get_presence_status(struct controller *ctrl, struct slot *slot)
|
static inline int get_presence_status(struct controller *ctrl,
|
||||||
|
struct slot *slot)
|
||||||
{
|
{
|
||||||
int presence_save = 0;
|
int presence_save = 0;
|
||||||
u8 hp_slot;
|
u8 hp_slot;
|
||||||
|
@ -696,7 +711,8 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot
|
||||||
hp_slot = slot->device - ctrl->slot_device_offset;
|
hp_slot = slot->device - ctrl->slot_device_offset;
|
||||||
|
|
||||||
tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
|
tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
|
||||||
presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02;
|
presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15))
|
||||||
|
>> hp_slot) & 0x02;
|
||||||
|
|
||||||
return presence_save;
|
return presence_save;
|
||||||
}
|
}
|
||||||
|
@ -718,5 +734,12 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#include <asm/pci_x86.h>
|
||||||
|
static inline int cpqhp_routing_table_length(void)
|
||||||
|
{
|
||||||
|
BUG_ON(cpqhp_routing_table == NULL);
|
||||||
|
return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) /
|
||||||
|
sizeof(struct irq_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -81,14 +81,15 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
|
||||||
|
|
||||||
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
||||||
if (change & (0x1L << hp_slot)) {
|
if (change & (0x1L << hp_slot)) {
|
||||||
/**********************************
|
/*
|
||||||
* this one changed.
|
* this one changed.
|
||||||
**********************************/
|
*/
|
||||||
func = cpqhp_slot_find(ctrl->bus,
|
func = cpqhp_slot_find(ctrl->bus,
|
||||||
(hp_slot + ctrl->slot_device_offset), 0);
|
(hp_slot + ctrl->slot_device_offset), 0);
|
||||||
|
|
||||||
/* this is the structure that tells the worker thread
|
/* this is the structure that tells the worker thread
|
||||||
*what to do */
|
* what to do
|
||||||
|
*/
|
||||||
taskInfo = &(ctrl->event_queue[ctrl->next_event]);
|
taskInfo = &(ctrl->event_queue[ctrl->next_event]);
|
||||||
ctrl->next_event = (ctrl->next_event + 1) % 10;
|
ctrl->next_event = (ctrl->next_event + 1) % 10;
|
||||||
taskInfo->hp_slot = hp_slot;
|
taskInfo->hp_slot = hp_slot;
|
||||||
|
@ -100,17 +101,17 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
|
||||||
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
|
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
|
||||||
|
|
||||||
if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
|
if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
|
||||||
/**********************************
|
/*
|
||||||
* Switch opened
|
* Switch opened
|
||||||
**********************************/
|
*/
|
||||||
|
|
||||||
func->switch_save = 0;
|
func->switch_save = 0;
|
||||||
|
|
||||||
taskInfo->event_type = INT_SWITCH_OPEN;
|
taskInfo->event_type = INT_SWITCH_OPEN;
|
||||||
} else {
|
} else {
|
||||||
/**********************************
|
/*
|
||||||
* Switch closed
|
* Switch closed
|
||||||
**********************************/
|
*/
|
||||||
|
|
||||||
func->switch_save = 0x10;
|
func->switch_save = 0x10;
|
||||||
|
|
||||||
|
@ -131,9 +132,8 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device)
|
||||||
{
|
{
|
||||||
struct slot *slot = ctrl->slot;
|
struct slot *slot = ctrl->slot;
|
||||||
|
|
||||||
while (slot && (slot->device != device)) {
|
while (slot && (slot->device != device))
|
||||||
slot = slot->next;
|
slot = slot->next;
|
||||||
}
|
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
@ -152,17 +152,17 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
|
||||||
if (!change)
|
if (!change)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/**********************************
|
/*
|
||||||
* Presence Change
|
* Presence Change
|
||||||
**********************************/
|
*/
|
||||||
dbg("cpqsbd: Presence/Notify input change.\n");
|
dbg("cpqsbd: Presence/Notify input change.\n");
|
||||||
dbg(" Changed bits are 0x%4.4x\n", change );
|
dbg(" Changed bits are 0x%4.4x\n", change );
|
||||||
|
|
||||||
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
||||||
if (change & (0x0101 << hp_slot)) {
|
if (change & (0x0101 << hp_slot)) {
|
||||||
/**********************************
|
/*
|
||||||
* this one changed.
|
* this one changed.
|
||||||
**********************************/
|
*/
|
||||||
func = cpqhp_slot_find(ctrl->bus,
|
func = cpqhp_slot_find(ctrl->bus,
|
||||||
(hp_slot + ctrl->slot_device_offset), 0);
|
(hp_slot + ctrl->slot_device_offset), 0);
|
||||||
|
|
||||||
|
@ -177,22 +177,23 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the switch closed, must be a button
|
/* If the switch closed, must be a button
|
||||||
* If not in button mode, nevermind */
|
* If not in button mode, nevermind
|
||||||
|
*/
|
||||||
if (func->switch_save && (ctrl->push_button == 1)) {
|
if (func->switch_save && (ctrl->push_button == 1)) {
|
||||||
temp_word = ctrl->ctrl_int_comp >> 16;
|
temp_word = ctrl->ctrl_int_comp >> 16;
|
||||||
temp_byte = (temp_word >> hp_slot) & 0x01;
|
temp_byte = (temp_word >> hp_slot) & 0x01;
|
||||||
temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02;
|
temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02;
|
||||||
|
|
||||||
if (temp_byte != func->presence_save) {
|
if (temp_byte != func->presence_save) {
|
||||||
/**************************************
|
/*
|
||||||
* button Pressed (doesn't do anything)
|
* button Pressed (doesn't do anything)
|
||||||
**************************************/
|
*/
|
||||||
dbg("hp_slot %d button pressed\n", hp_slot);
|
dbg("hp_slot %d button pressed\n", hp_slot);
|
||||||
taskInfo->event_type = INT_BUTTON_PRESS;
|
taskInfo->event_type = INT_BUTTON_PRESS;
|
||||||
} else {
|
} else {
|
||||||
/**********************************
|
/*
|
||||||
* button Released - TAKE ACTION!!!!
|
* button Released - TAKE ACTION!!!!
|
||||||
**********************************/
|
*/
|
||||||
dbg("hp_slot %d button released\n", hp_slot);
|
dbg("hp_slot %d button released\n", hp_slot);
|
||||||
taskInfo->event_type = INT_BUTTON_RELEASE;
|
taskInfo->event_type = INT_BUTTON_RELEASE;
|
||||||
|
|
||||||
|
@ -210,7 +211,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Switch is open, assume a presence change
|
/* Switch is open, assume a presence change
|
||||||
* Save the presence state */
|
* Save the presence state
|
||||||
|
*/
|
||||||
temp_word = ctrl->ctrl_int_comp >> 16;
|
temp_word = ctrl->ctrl_int_comp >> 16;
|
||||||
func->presence_save = (temp_word >> hp_slot) & 0x01;
|
func->presence_save = (temp_word >> hp_slot) & 0x01;
|
||||||
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
|
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
|
||||||
|
@ -241,17 +243,17 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl)
|
||||||
if (!change)
|
if (!change)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/**********************************
|
/*
|
||||||
* power fault
|
* power fault
|
||||||
**********************************/
|
*/
|
||||||
|
|
||||||
info("power fault interrupt\n");
|
info("power fault interrupt\n");
|
||||||
|
|
||||||
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
|
||||||
if (change & (0x01 << hp_slot)) {
|
if (change & (0x01 << hp_slot)) {
|
||||||
/**********************************
|
/*
|
||||||
* this one changed.
|
* this one changed.
|
||||||
**********************************/
|
*/
|
||||||
func = cpqhp_slot_find(ctrl->bus,
|
func = cpqhp_slot_find(ctrl->bus,
|
||||||
(hp_slot + ctrl->slot_device_offset), 0);
|
(hp_slot + ctrl->slot_device_offset), 0);
|
||||||
|
|
||||||
|
@ -262,16 +264,16 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl)
|
||||||
rc++;
|
rc++;
|
||||||
|
|
||||||
if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) {
|
if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) {
|
||||||
/**********************************
|
/*
|
||||||
* power fault Cleared
|
* power fault Cleared
|
||||||
**********************************/
|
*/
|
||||||
func->status = 0x00;
|
func->status = 0x00;
|
||||||
|
|
||||||
taskInfo->event_type = INT_POWER_FAULT_CLEAR;
|
taskInfo->event_type = INT_POWER_FAULT_CLEAR;
|
||||||
} else {
|
} else {
|
||||||
/**********************************
|
/*
|
||||||
* power fault
|
* power fault
|
||||||
**********************************/
|
*/
|
||||||
taskInfo->event_type = INT_POWER_FAULT;
|
taskInfo->event_type = INT_POWER_FAULT;
|
||||||
|
|
||||||
if (ctrl->rev < 4) {
|
if (ctrl->rev < 4) {
|
||||||
|
@ -432,13 +434,15 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h
|
||||||
|
|
||||||
|
|
||||||
/* If we got here, there the bridge requires some of the resource, but
|
/* If we got here, there the bridge requires some of the resource, but
|
||||||
* we may be able to split some off of the front */
|
* we may be able to split some off of the front
|
||||||
|
*/
|
||||||
|
|
||||||
node = *head;
|
node = *head;
|
||||||
|
|
||||||
if (node->length & (alignment -1)) {
|
if (node->length & (alignment -1)) {
|
||||||
/* this one isn't an aligned length, so we'll make a new entry
|
/* this one isn't an aligned length, so we'll make a new entry
|
||||||
* and split it up. */
|
* and split it up.
|
||||||
|
*/
|
||||||
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
||||||
|
|
||||||
if (!split_node)
|
if (!split_node)
|
||||||
|
@ -544,10 +548,10 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
|
||||||
if (!(*head))
|
if (!(*head))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ( cpqhp_resource_sort_and_combine(head) )
|
if (cpqhp_resource_sort_and_combine(head))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ( sort_by_size(head) )
|
if (sort_by_size(head))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (node = *head; node; node = node->next) {
|
for (node = *head; node; node = node->next) {
|
||||||
|
@ -556,7 +560,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
|
||||||
|
|
||||||
if (node->base & (size - 1)) {
|
if (node->base & (size - 1)) {
|
||||||
/* this one isn't base aligned properly
|
/* this one isn't base aligned properly
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
temp_dword = (node->base | (size-1)) + 1;
|
temp_dword = (node->base | (size-1)) + 1;
|
||||||
|
|
||||||
/* Short circuit if adjusted size is too small */
|
/* Short circuit if adjusted size is too small */
|
||||||
|
@ -581,7 +586,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
|
||||||
/* Don't need to check if too small since we already did */
|
/* Don't need to check if too small since we already did */
|
||||||
if (node->length > size) {
|
if (node->length > size) {
|
||||||
/* this one is longer than we need
|
/* this one is longer than we need
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
||||||
|
|
||||||
if (!split_node)
|
if (!split_node)
|
||||||
|
@ -601,7 +607,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* If we got here, then it is the right size
|
/* If we got here, then it is the right size
|
||||||
* Now take it out of the list and break */
|
* Now take it out of the list and break
|
||||||
|
*/
|
||||||
if (*head == node) {
|
if (*head == node) {
|
||||||
*head = node->next;
|
*head = node->next;
|
||||||
} else {
|
} else {
|
||||||
|
@ -643,13 +650,15 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz
|
||||||
|
|
||||||
for (max = *head; max; max = max->next) {
|
for (max = *head; max; max = max->next) {
|
||||||
/* If not big enough we could probably just bail,
|
/* If not big enough we could probably just bail,
|
||||||
* instead we'll continue to the next. */
|
* instead we'll continue to the next.
|
||||||
|
*/
|
||||||
if (max->length < size)
|
if (max->length < size)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (max->base & (size - 1)) {
|
if (max->base & (size - 1)) {
|
||||||
/* this one isn't base aligned properly
|
/* this one isn't base aligned properly
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
temp_dword = (max->base | (size-1)) + 1;
|
temp_dword = (max->base | (size-1)) + 1;
|
||||||
|
|
||||||
/* Short circuit if adjusted size is too small */
|
/* Short circuit if adjusted size is too small */
|
||||||
|
@ -672,7 +681,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz
|
||||||
|
|
||||||
if ((max->base + max->length) & (size - 1)) {
|
if ((max->base + max->length) & (size - 1)) {
|
||||||
/* this one isn't end aligned properly at the top
|
/* this one isn't end aligned properly at the top
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
||||||
|
|
||||||
if (!split_node)
|
if (!split_node)
|
||||||
|
@ -744,7 +754,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
|
||||||
if (node->base & (size - 1)) {
|
if (node->base & (size - 1)) {
|
||||||
dbg("%s: not aligned\n", __func__);
|
dbg("%s: not aligned\n", __func__);
|
||||||
/* this one isn't base aligned properly
|
/* this one isn't base aligned properly
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
temp_dword = (node->base | (size-1)) + 1;
|
temp_dword = (node->base | (size-1)) + 1;
|
||||||
|
|
||||||
/* Short circuit if adjusted size is too small */
|
/* Short circuit if adjusted size is too small */
|
||||||
|
@ -769,7 +780,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
|
||||||
if (node->length > size) {
|
if (node->length > size) {
|
||||||
dbg("%s: too big\n", __func__);
|
dbg("%s: too big\n", __func__);
|
||||||
/* this one is longer than we need
|
/* this one is longer than we need
|
||||||
* so we'll make a new entry and split it up */
|
* so we'll make a new entry and split it up
|
||||||
|
*/
|
||||||
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
|
||||||
|
|
||||||
if (!split_node)
|
if (!split_node)
|
||||||
|
@ -888,17 +900,17 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
|
||||||
|
|
||||||
|
|
||||||
misc = readw(ctrl->hpc_reg + MISC);
|
misc = readw(ctrl->hpc_reg + MISC);
|
||||||
/***************************************
|
/*
|
||||||
* Check to see if it was our interrupt
|
* Check to see if it was our interrupt
|
||||||
***************************************/
|
*/
|
||||||
if (!(misc & 0x000C)) {
|
if (!(misc & 0x000C)) {
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (misc & 0x0004) {
|
if (misc & 0x0004) {
|
||||||
/**********************************
|
/*
|
||||||
* Serial Output interrupt Pending
|
* Serial Output interrupt Pending
|
||||||
**********************************/
|
*/
|
||||||
|
|
||||||
/* Clear the interrupt */
|
/* Clear the interrupt */
|
||||||
misc |= 0x0004;
|
misc |= 0x0004;
|
||||||
|
@ -961,11 +973,8 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
|
||||||
struct pci_func *next;
|
struct pci_func *next;
|
||||||
|
|
||||||
new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
|
new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
|
||||||
if (new_slot == NULL) {
|
if (new_slot == NULL)
|
||||||
/* I'm not dead yet!
|
|
||||||
* You will be. */
|
|
||||||
return new_slot;
|
return new_slot;
|
||||||
}
|
|
||||||
|
|
||||||
new_slot->next = NULL;
|
new_slot->next = NULL;
|
||||||
new_slot->configured = 1;
|
new_slot->configured = 1;
|
||||||
|
@ -996,10 +1005,8 @@ static int slot_remove(struct pci_func * old_slot)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
next = cpqhp_slot_list[old_slot->bus];
|
next = cpqhp_slot_list[old_slot->bus];
|
||||||
|
if (next == NULL)
|
||||||
if (next == NULL) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (next == old_slot) {
|
if (next == old_slot) {
|
||||||
cpqhp_slot_list[old_slot->bus] = old_slot->next;
|
cpqhp_slot_list[old_slot->bus] = old_slot->next;
|
||||||
|
@ -1008,9 +1015,8 @@ static int slot_remove(struct pci_func * old_slot)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((next->next != old_slot) && (next->next != NULL)) {
|
while ((next->next != old_slot) && (next->next != NULL))
|
||||||
next = next->next;
|
next = next->next;
|
||||||
}
|
|
||||||
|
|
||||||
if (next->next == old_slot) {
|
if (next->next == old_slot) {
|
||||||
next->next = old_slot->next;
|
next->next = old_slot->next;
|
||||||
|
@ -1040,9 +1046,8 @@ static int bridge_slot_remove(struct pci_func *bridge)
|
||||||
for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
|
for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
|
||||||
next = cpqhp_slot_list[tempBus];
|
next = cpqhp_slot_list[tempBus];
|
||||||
|
|
||||||
while (!slot_remove(next)) {
|
while (!slot_remove(next))
|
||||||
next = cpqhp_slot_list[tempBus];
|
next = cpqhp_slot_list[tempBus];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next = cpqhp_slot_list[bridge->bus];
|
next = cpqhp_slot_list[bridge->bus];
|
||||||
|
@ -1135,7 +1140,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* We don't allow freq/mode changes if we find another adapter running
|
/* We don't allow freq/mode changes if we find another adapter running
|
||||||
* in another slot on this controller */
|
* in another slot on this controller
|
||||||
|
*/
|
||||||
for(slot = ctrl->slot; slot; slot = slot->next) {
|
for(slot = ctrl->slot; slot; slot = slot->next) {
|
||||||
if (slot->device == (hp_slot + ctrl->slot_device_offset))
|
if (slot->device == (hp_slot + ctrl->slot_device_offset))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1145,7 +1151,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
|
||||||
continue;
|
continue;
|
||||||
/* If another adapter is running on the same segment but at a
|
/* If another adapter is running on the same segment but at a
|
||||||
* lower speed/mode, we allow the new adapter to function at
|
* lower speed/mode, we allow the new adapter to function at
|
||||||
* this rate if supported */
|
* this rate if supported
|
||||||
|
*/
|
||||||
if (ctrl->speed < adapter_speed)
|
if (ctrl->speed < adapter_speed)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1153,7 +1160,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the controller doesn't support freq/mode changes and the
|
/* If the controller doesn't support freq/mode changes and the
|
||||||
* controller is running at a higher mode, we bail */
|
* controller is running at a higher mode, we bail
|
||||||
|
*/
|
||||||
if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
|
if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -1162,7 +1170,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* We try to set the max speed supported by both the adapter and
|
/* We try to set the max speed supported by both the adapter and
|
||||||
* controller */
|
* controller
|
||||||
|
*/
|
||||||
if (ctrl->speed_capability < adapter_speed) {
|
if (ctrl->speed_capability < adapter_speed) {
|
||||||
if (ctrl->speed == ctrl->speed_capability)
|
if (ctrl->speed == ctrl->speed_capability)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1244,7 +1253,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the following routines constitute the bulk of the
|
/* the following routines constitute the bulk of the
|
||||||
hotplug controller logic
|
* hotplug controller logic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1268,17 +1277,17 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
|
||||||
|
|
||||||
hp_slot = func->device - ctrl->slot_device_offset;
|
hp_slot = func->device - ctrl->slot_device_offset;
|
||||||
|
|
||||||
if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) {
|
/*
|
||||||
/**********************************
|
* The switch is open.
|
||||||
* The switch is open.
|
*/
|
||||||
**********************************/
|
if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot))
|
||||||
rc = INTERLOCK_OPEN;
|
rc = INTERLOCK_OPEN;
|
||||||
} else if (is_slot_enabled (ctrl, hp_slot)) {
|
/*
|
||||||
/**********************************
|
* The board is already on
|
||||||
* The board is already on
|
*/
|
||||||
**********************************/
|
else if (is_slot_enabled (ctrl, hp_slot))
|
||||||
rc = CARD_FUNCTIONING;
|
rc = CARD_FUNCTIONING;
|
||||||
} else {
|
else {
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->crit_sect);
|
||||||
|
|
||||||
/* turn on board without attaching to the bus */
|
/* turn on board without attaching to the bus */
|
||||||
|
@ -1352,7 +1361,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
|
||||||
* Get slot won't work for devices behind
|
* Get slot won't work for devices behind
|
||||||
* bridges, but in this case it will always be
|
* bridges, but in this case it will always be
|
||||||
* called for the "base" bus/dev/func of an
|
* called for the "base" bus/dev/func of an
|
||||||
* adapter. */
|
* adapter.
|
||||||
|
*/
|
||||||
|
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->crit_sect);
|
||||||
|
|
||||||
|
@ -1377,7 +1387,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
|
||||||
|
|
||||||
* Get slot won't work for devices behind bridges, but
|
* Get slot won't work for devices behind bridges, but
|
||||||
* in this case it will always be called for the "base"
|
* in this case it will always be called for the "base"
|
||||||
* bus/dev/func of an adapter. */
|
* bus/dev/func of an adapter.
|
||||||
|
*/
|
||||||
|
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->crit_sect);
|
||||||
|
|
||||||
|
@ -1434,7 +1445,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
|
||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
|
|
||||||
/* Change bits in slot power register to force another shift out
|
/* Change bits in slot power register to force another shift out
|
||||||
* NOTE: this is to work around the timer bug */
|
* NOTE: this is to work around the timer bug
|
||||||
|
*/
|
||||||
temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
|
temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
|
||||||
writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
|
writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
|
||||||
writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
|
writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
|
||||||
|
@ -1521,7 +1533,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All F's is an empty slot or an invalid board */
|
/* All F's is an empty slot or an invalid board */
|
||||||
if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */
|
if (temp_register != 0xFFFFFFFF) {
|
||||||
res_lists.io_head = ctrl->io_head;
|
res_lists.io_head = ctrl->io_head;
|
||||||
res_lists.mem_head = ctrl->mem_head;
|
res_lists.mem_head = ctrl->mem_head;
|
||||||
res_lists.p_mem_head = ctrl->p_mem_head;
|
res_lists.p_mem_head = ctrl->p_mem_head;
|
||||||
|
@ -1570,9 +1582,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
|
||||||
index = 0;
|
index = 0;
|
||||||
do {
|
do {
|
||||||
new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
|
new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
|
||||||
if (new_slot && !new_slot->pci_dev) {
|
if (new_slot && !new_slot->pci_dev)
|
||||||
cpqhp_configure_device(ctrl, new_slot);
|
cpqhp_configure_device(ctrl, new_slot);
|
||||||
}
|
|
||||||
} while (new_slot);
|
} while (new_slot);
|
||||||
|
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->crit_sect);
|
||||||
|
@ -2113,9 +2124,8 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
|
||||||
|
|
||||||
/* If the VGA Enable bit is set, remove isn't
|
/* If the VGA Enable bit is set, remove isn't
|
||||||
* supported */
|
* supported */
|
||||||
if (BCR & PCI_BRIDGE_CTL_VGA) {
|
if (BCR & PCI_BRIDGE_CTL_VGA)
|
||||||
rc = REMOVE_NOT_SUPPORTED;
|
rc = REMOVE_NOT_SUPPORTED;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2183,67 +2193,67 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num)
|
||||||
num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f;
|
num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f;
|
||||||
|
|
||||||
switch (test_num) {
|
switch (test_num) {
|
||||||
case 1:
|
case 1:
|
||||||
/* Do stuff here! */
|
/* Do stuff here! */
|
||||||
|
|
||||||
/* Do that funky LED thing */
|
/* Do that funky LED thing */
|
||||||
/* so we can restore them later */
|
/* so we can restore them later */
|
||||||
save_LED = readl(ctrl->hpc_reg + LED_CONTROL);
|
save_LED = readl(ctrl->hpc_reg + LED_CONTROL);
|
||||||
work_LED = 0x01010101;
|
work_LED = 0x01010101;
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
||||||
|
|
||||||
work_LED = 0x01010000;
|
work_LED = 0x01010000;
|
||||||
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
|
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
||||||
|
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
||||||
|
work_LED = 0x00000101;
|
||||||
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
|
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
||||||
|
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
||||||
|
|
||||||
|
work_LED = 0x01010000;
|
||||||
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
|
for (loop = 0; loop < num_of_slots; loop++) {
|
||||||
|
set_SOGO(ctrl);
|
||||||
|
|
||||||
|
/* Wait for SOGO interrupt */
|
||||||
|
wait_for_ctrl_irq (ctrl);
|
||||||
|
|
||||||
|
/* Get ready for next iteration */
|
||||||
|
long_delay((3*HZ)/10);
|
||||||
|
work_LED = work_LED >> 16;
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
|
||||||
work_LED = 0x00000101;
|
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 0);
|
|
||||||
switch_leds(ctrl, num_of_slots, &work_LED, 1);
|
|
||||||
|
|
||||||
work_LED = 0x01010000;
|
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
for (loop = 0; loop < num_of_slots; loop++) {
|
|
||||||
set_SOGO(ctrl);
|
|
||||||
|
|
||||||
/* Wait for SOGO interrupt */
|
|
||||||
wait_for_ctrl_irq (ctrl);
|
|
||||||
|
|
||||||
/* Get ready for next iteration */
|
|
||||||
long_delay((3*HZ)/10);
|
|
||||||
work_LED = work_LED >> 16;
|
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
|
|
||||||
set_SOGO(ctrl);
|
|
||||||
|
|
||||||
/* Wait for SOGO interrupt */
|
|
||||||
wait_for_ctrl_irq (ctrl);
|
|
||||||
|
|
||||||
/* Get ready for next iteration */
|
|
||||||
long_delay((3*HZ)/10);
|
|
||||||
work_LED = work_LED << 16;
|
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
work_LED = work_LED << 1;
|
|
||||||
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* put it back the way it was */
|
|
||||||
writel(save_LED, ctrl->hpc_reg + LED_CONTROL);
|
|
||||||
|
|
||||||
set_SOGO(ctrl);
|
set_SOGO(ctrl);
|
||||||
|
|
||||||
/* Wait for SOBS to be unset */
|
/* Wait for SOGO interrupt */
|
||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
break;
|
|
||||||
case 2:
|
/* Get ready for next iteration */
|
||||||
/* Do other stuff here! */
|
long_delay((3*HZ)/10);
|
||||||
break;
|
work_LED = work_LED << 16;
|
||||||
case 3:
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
/* and more... */
|
work_LED = work_LED << 1;
|
||||||
break;
|
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put it back the way it was */
|
||||||
|
writel(save_LED, ctrl->hpc_reg + LED_CONTROL);
|
||||||
|
|
||||||
|
set_SOGO(ctrl);
|
||||||
|
|
||||||
|
/* Wait for SOBS to be unset */
|
||||||
|
wait_for_ctrl_irq (ctrl);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Do other stuff here! */
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* and more... */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2312,9 +2322,9 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func
|
||||||
while ((function < max_functions) && (!stop_it)) {
|
while ((function < max_functions) && (!stop_it)) {
|
||||||
pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
|
pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
|
||||||
|
|
||||||
if (ID == 0xFFFFFFFF) { /* There's nothing there. */
|
if (ID == 0xFFFFFFFF) {
|
||||||
function++;
|
function++;
|
||||||
} else { /* There's something there */
|
} else {
|
||||||
/* Setup slot structure. */
|
/* Setup slot structure. */
|
||||||
new_slot = cpqhp_slot_create(func->bus);
|
new_slot = cpqhp_slot_create(func->bus);
|
||||||
|
|
||||||
|
@ -2339,8 +2349,8 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Configuration logic that involves the hotplug data structures and
|
* Configuration logic that involves the hotplug data structures and
|
||||||
their bookkeeping
|
* their bookkeeping
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -2393,7 +2403,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
|
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||||
/* set Primary bus */
|
/* set Primary bus */
|
||||||
dbg("set Primary bus = %d\n", func->bus);
|
dbg("set Primary bus = %d\n", func->bus);
|
||||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
|
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
|
||||||
|
@ -2484,7 +2494,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||||
temp_resources.irqs = &irqs;
|
temp_resources.irqs = &irqs;
|
||||||
|
|
||||||
/* Make copies of the nodes we are going to pass down so that
|
/* Make copies of the nodes we are going to pass down so that
|
||||||
* if there is a problem,we can just use these to free resources */
|
* if there is a problem,we can just use these to free resources
|
||||||
|
*/
|
||||||
hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL);
|
hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL);
|
||||||
hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL);
|
hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL);
|
||||||
hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL);
|
hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL);
|
||||||
|
@ -2556,7 +2567,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||||
temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
|
temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
|
||||||
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
|
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
|
||||||
|
|
||||||
/* Adjust this to compensate for extra adjustment in first loop */
|
/* Adjust this to compensate for extra adjustment in first loop
|
||||||
|
*/
|
||||||
irqs.barber_pole--;
|
irqs.barber_pole--;
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -2933,11 +2945,10 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||||
/* Program IRQ based on card type */
|
/* Program IRQ based on card type */
|
||||||
rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
|
rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
|
||||||
|
|
||||||
if (class_code == PCI_BASE_CLASS_STORAGE) {
|
if (class_code == PCI_BASE_CLASS_STORAGE)
|
||||||
IRQ = cpqhp_disk_irq;
|
IRQ = cpqhp_disk_irq;
|
||||||
} else {
|
else
|
||||||
IRQ = cpqhp_nic_irq;
|
IRQ = cpqhp_nic_irq;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IRQ Line */
|
/* IRQ Line */
|
||||||
|
|
|
@ -94,12 +94,13 @@ static u8 evbuffer[1024];
|
||||||
|
|
||||||
static void __iomem *compaq_int15_entry_point;
|
static void __iomem *compaq_int15_entry_point;
|
||||||
|
|
||||||
static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */
|
/* lock for ordering int15_bios_call() */
|
||||||
|
static spinlock_t int15_lock;
|
||||||
|
|
||||||
|
|
||||||
/* This is a series of function that deals with
|
/* This is a series of function that deals with
|
||||||
setting & getting the hotplug resource table in some environment variable.
|
* setting & getting the hotplug resource table in some environment variable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We really shouldn't be doing this unless there is a _very_ good reason to!!!
|
* We really shouldn't be doing this unless there is a _very_ good reason to!!!
|
||||||
|
@ -210,14 +211,16 @@ static int load_HRT (void __iomem *rom_start)
|
||||||
|
|
||||||
available = 1024;
|
available = 1024;
|
||||||
|
|
||||||
// Now load the EV
|
/* Now load the EV */
|
||||||
temp_dword = available;
|
temp_dword = available;
|
||||||
|
|
||||||
rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
|
rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
|
||||||
|
|
||||||
evbuffer_length = temp_dword;
|
evbuffer_length = temp_dword;
|
||||||
|
|
||||||
// We're maintaining the resource lists so write FF to invalidate old info
|
/* We're maintaining the resource lists so write FF to invalidate old
|
||||||
|
* info
|
||||||
|
*/
|
||||||
temp_dword = 1;
|
temp_dword = 1;
|
||||||
|
|
||||||
rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
|
rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
|
||||||
|
@ -264,12 +267,12 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
|
|
||||||
ctrl = cpqhp_ctrl_list;
|
ctrl = cpqhp_ctrl_list;
|
||||||
|
|
||||||
// The revision of this structure
|
/* The revision of this structure */
|
||||||
rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
|
rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// The number of controllers
|
/* The number of controllers */
|
||||||
rc = add_byte( &pFill, 1, &usedbytes, &available);
|
rc = add_byte( &pFill, 1, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
@ -279,27 +282,27 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
|
|
||||||
numCtrl++;
|
numCtrl++;
|
||||||
|
|
||||||
// The bus number
|
/* The bus number */
|
||||||
rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
|
rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// The device Number
|
/* The device Number */
|
||||||
rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
|
rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// The function Number
|
/* The function Number */
|
||||||
rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
|
rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// Skip the number of available entries
|
/* Skip the number of available entries */
|
||||||
rc = add_dword( &pFill, 0, &usedbytes, &available);
|
rc = add_dword( &pFill, 0, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// Figure out memory Available
|
/* Figure out memory Available */
|
||||||
|
|
||||||
resNode = ctrl->mem_head;
|
resNode = ctrl->mem_head;
|
||||||
|
|
||||||
|
@ -308,12 +311,12 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
while (resNode) {
|
while (resNode) {
|
||||||
loop ++;
|
loop ++;
|
||||||
|
|
||||||
// base
|
/* base */
|
||||||
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// length
|
/* length */
|
||||||
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
@ -321,10 +324,10 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
resNode = resNode->next;
|
resNode = resNode->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the number of entries
|
/* Fill in the number of entries */
|
||||||
p_ev_ctrl->mem_avail = loop;
|
p_ev_ctrl->mem_avail = loop;
|
||||||
|
|
||||||
// Figure out prefetchable memory Available
|
/* Figure out prefetchable memory Available */
|
||||||
|
|
||||||
resNode = ctrl->p_mem_head;
|
resNode = ctrl->p_mem_head;
|
||||||
|
|
||||||
|
@ -333,12 +336,12 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
while (resNode) {
|
while (resNode) {
|
||||||
loop ++;
|
loop ++;
|
||||||
|
|
||||||
// base
|
/* base */
|
||||||
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// length
|
/* length */
|
||||||
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
@ -346,10 +349,10 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
resNode = resNode->next;
|
resNode = resNode->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the number of entries
|
/* Fill in the number of entries */
|
||||||
p_ev_ctrl->p_mem_avail = loop;
|
p_ev_ctrl->p_mem_avail = loop;
|
||||||
|
|
||||||
// Figure out IO Available
|
/* Figure out IO Available */
|
||||||
|
|
||||||
resNode = ctrl->io_head;
|
resNode = ctrl->io_head;
|
||||||
|
|
||||||
|
@ -358,12 +361,12 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
while (resNode) {
|
while (resNode) {
|
||||||
loop ++;
|
loop ++;
|
||||||
|
|
||||||
// base
|
/* base */
|
||||||
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// length
|
/* length */
|
||||||
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
@ -371,10 +374,10 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
resNode = resNode->next;
|
resNode = resNode->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the number of entries
|
/* Fill in the number of entries */
|
||||||
p_ev_ctrl->io_avail = loop;
|
p_ev_ctrl->io_avail = loop;
|
||||||
|
|
||||||
// Figure out bus Available
|
/* Figure out bus Available */
|
||||||
|
|
||||||
resNode = ctrl->bus_head;
|
resNode = ctrl->bus_head;
|
||||||
|
|
||||||
|
@ -383,12 +386,12 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
while (resNode) {
|
while (resNode) {
|
||||||
loop ++;
|
loop ++;
|
||||||
|
|
||||||
// base
|
/* base */
|
||||||
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
|
||||||
// length
|
/* length */
|
||||||
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
|
||||||
if (rc)
|
if (rc)
|
||||||
return(rc);
|
return(rc);
|
||||||
|
@ -396,7 +399,7 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
resNode = resNode->next;
|
resNode = resNode->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the number of entries
|
/* Fill in the number of entries */
|
||||||
p_ev_ctrl->bus_avail = loop;
|
p_ev_ctrl->bus_avail = loop;
|
||||||
|
|
||||||
ctrl = ctrl->next;
|
ctrl = ctrl->next;
|
||||||
|
@ -404,7 +407,7 @@ static u32 store_HRT (void __iomem *rom_start)
|
||||||
|
|
||||||
p_EV_header->num_of_ctrl = numCtrl;
|
p_EV_header->num_of_ctrl = numCtrl;
|
||||||
|
|
||||||
// Now store the EV
|
/* Now store the EV */
|
||||||
|
|
||||||
temp_dword = usedbytes;
|
temp_dword = usedbytes;
|
||||||
|
|
||||||
|
@ -449,20 +452,21 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
|
||||||
struct ev_hrt_header *p_EV_header;
|
struct ev_hrt_header *p_EV_header;
|
||||||
|
|
||||||
if (!evbuffer_init) {
|
if (!evbuffer_init) {
|
||||||
// Read the resource list information in from NVRAM
|
/* Read the resource list information in from NVRAM */
|
||||||
if (load_HRT(rom_start))
|
if (load_HRT(rom_start))
|
||||||
memset (evbuffer, 0, 1024);
|
memset (evbuffer, 0, 1024);
|
||||||
|
|
||||||
evbuffer_init = 1;
|
evbuffer_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we saved information in NVRAM, use it now
|
/* If we saved information in NVRAM, use it now */
|
||||||
p_EV_header = (struct ev_hrt_header *) evbuffer;
|
p_EV_header = (struct ev_hrt_header *) evbuffer;
|
||||||
|
|
||||||
// The following code is for systems where version 1.0 of this
|
/* The following code is for systems where version 1.0 of this
|
||||||
// driver has been loaded, but doesn't support the hardware.
|
* driver has been loaded, but doesn't support the hardware.
|
||||||
// In that case, the driver would incorrectly store something
|
* In that case, the driver would incorrectly store something
|
||||||
// in NVRAM.
|
* in NVRAM.
|
||||||
|
*/
|
||||||
if ((p_EV_header->Version == 2) ||
|
if ((p_EV_header->Version == 2) ||
|
||||||
((p_EV_header->Version == 1) && !ctrl->push_flag)) {
|
((p_EV_header->Version == 1) && !ctrl->push_flag)) {
|
||||||
p_byte = &(p_EV_header->next);
|
p_byte = &(p_EV_header->next);
|
||||||
|
@ -491,7 +495,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
|
||||||
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
|
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// Skip forward to the next entry
|
/* Skip forward to the next entry */
|
||||||
p_byte += (nummem + numpmem + numio + numbus) * 8;
|
p_byte += (nummem + numpmem + numio + numbus) * 8;
|
||||||
|
|
||||||
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
|
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
|
||||||
|
@ -629,8 +633,9 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
|
||||||
ctrl->bus_head = bus_node;
|
ctrl->bus_head = bus_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all of the following fail, we don't have any resources for
|
/* If all of the following fail, we don't have any resources for
|
||||||
// hot plug add
|
* hot plug add
|
||||||
|
*/
|
||||||
rc = 1;
|
rc = 1;
|
||||||
rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
|
rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
|
||||||
rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
|
rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1318,7 +1318,6 @@ int ibmphp_do_disable_slot(struct slot *slot_cur)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
|
struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = ibmphp_disable_slot,
|
.disable_slot = ibmphp_disable_slot,
|
||||||
|
@ -1421,3 +1420,4 @@ static void __exit ibmphp_exit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(ibmphp_init);
|
module_init(ibmphp_init);
|
||||||
|
module_exit(ibmphp_exit);
|
||||||
|
|
|
@ -347,125 +347,129 @@ static struct pci_slot_attribute hotplug_slot_attr_test = {
|
||||||
.store = test_write_file
|
.store = test_write_file
|
||||||
};
|
};
|
||||||
|
|
||||||
static int has_power_file(struct pci_slot *pci_slot)
|
static bool has_power_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if ((slot->ops->enable_slot) ||
|
if ((slot->ops->enable_slot) ||
|
||||||
(slot->ops->disable_slot) ||
|
(slot->ops->disable_slot) ||
|
||||||
(slot->ops->get_power_status))
|
(slot->ops->get_power_status))
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_attention_file(struct pci_slot *pci_slot)
|
static bool has_attention_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if ((slot->ops->set_attention_status) ||
|
if ((slot->ops->set_attention_status) ||
|
||||||
(slot->ops->get_attention_status))
|
(slot->ops->get_attention_status))
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_latch_file(struct pci_slot *pci_slot)
|
static bool has_latch_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if (slot->ops->get_latch_status)
|
if (slot->ops->get_latch_status)
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_adapter_file(struct pci_slot *pci_slot)
|
static bool has_adapter_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if (slot->ops->get_adapter_status)
|
if (slot->ops->get_adapter_status)
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_max_bus_speed_file(struct pci_slot *pci_slot)
|
static bool has_max_bus_speed_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if (slot->ops->get_max_bus_speed)
|
if (slot->ops->get_max_bus_speed)
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
|
static bool has_cur_bus_speed_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if (slot->ops->get_cur_bus_speed)
|
if (slot->ops->get_cur_bus_speed)
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int has_test_file(struct pci_slot *pci_slot)
|
static bool has_test_file(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *slot = pci_slot->hotplug;
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
if ((!slot) || (!slot->ops))
|
if ((!slot) || (!slot->ops))
|
||||||
return -ENODEV;
|
return false;
|
||||||
if (slot->ops->hardware_test)
|
if (slot->ops->hardware_test)
|
||||||
return 0;
|
return true;
|
||||||
return -ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fs_add_slot(struct pci_slot *slot)
|
static int fs_add_slot(struct pci_slot *slot)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (has_power_file(slot) == 0) {
|
/* Create symbolic link to the hotplug driver module */
|
||||||
retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
pci_hp_create_module_link(slot);
|
||||||
|
|
||||||
|
if (has_power_file(slot)) {
|
||||||
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_power.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_power;
|
goto exit_power;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_attention_file(slot) == 0) {
|
if (has_attention_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_attention.attr);
|
&hotplug_slot_attr_attention.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_attention;
|
goto exit_attention;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_latch_file(slot) == 0) {
|
if (has_latch_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_latch.attr);
|
&hotplug_slot_attr_latch.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_latch;
|
goto exit_latch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_adapter_file(slot) == 0) {
|
if (has_adapter_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_presence.attr);
|
&hotplug_slot_attr_presence.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_adapter;
|
goto exit_adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_max_bus_speed_file(slot) == 0) {
|
if (has_max_bus_speed_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_max_bus_speed.attr);
|
&hotplug_slot_attr_max_bus_speed.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_max_speed;
|
goto exit_max_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_cur_bus_speed_file(slot) == 0) {
|
if (has_cur_bus_speed_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_cur_bus_speed.attr);
|
&hotplug_slot_attr_cur_bus_speed.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_cur_speed;
|
goto exit_cur_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_test_file(slot) == 0) {
|
if (has_test_file(slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&slot->kobj,
|
||||||
&hotplug_slot_attr_test.attr);
|
&hotplug_slot_attr_test.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
|
@ -475,55 +479,61 @@ static int fs_add_slot(struct pci_slot *slot)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
exit_test:
|
exit_test:
|
||||||
if (has_cur_bus_speed_file(slot) == 0)
|
if (has_cur_bus_speed_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_cur_bus_speed.attr);
|
||||||
exit_cur_speed:
|
exit_cur_speed:
|
||||||
if (has_max_bus_speed_file(slot) == 0)
|
if (has_max_bus_speed_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_max_bus_speed.attr);
|
||||||
exit_max_speed:
|
exit_max_speed:
|
||||||
if (has_adapter_file(slot) == 0)
|
if (has_adapter_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_presence.attr);
|
||||||
exit_adapter:
|
exit_adapter:
|
||||||
if (has_latch_file(slot) == 0)
|
if (has_latch_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
||||||
|
|
||||||
exit_latch:
|
exit_latch:
|
||||||
if (has_attention_file(slot) == 0)
|
if (has_attention_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_attention.attr);
|
||||||
exit_attention:
|
exit_attention:
|
||||||
if (has_power_file(slot) == 0)
|
if (has_power_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
||||||
exit_power:
|
exit_power:
|
||||||
|
pci_hp_remove_module_link(slot);
|
||||||
exit:
|
exit:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fs_remove_slot(struct pci_slot *slot)
|
static void fs_remove_slot(struct pci_slot *slot)
|
||||||
{
|
{
|
||||||
if (has_power_file(slot) == 0)
|
if (has_power_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
||||||
|
|
||||||
if (has_attention_file(slot) == 0)
|
if (has_attention_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_attention.attr);
|
||||||
|
|
||||||
if (has_latch_file(slot) == 0)
|
if (has_latch_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
||||||
|
|
||||||
if (has_adapter_file(slot) == 0)
|
if (has_adapter_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_presence.attr);
|
||||||
|
|
||||||
if (has_max_bus_speed_file(slot) == 0)
|
if (has_max_bus_speed_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_max_bus_speed.attr);
|
||||||
|
|
||||||
if (has_cur_bus_speed_file(slot) == 0)
|
if (has_cur_bus_speed_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
|
sysfs_remove_file(&slot->kobj,
|
||||||
|
&hotplug_slot_attr_cur_bus_speed.attr);
|
||||||
|
|
||||||
if (has_test_file(slot) == 0)
|
if (has_test_file(slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
|
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
|
||||||
|
|
||||||
|
pci_hp_remove_module_link(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hotplug_slot *get_slot_from_name (const char *name)
|
static struct hotplug_slot *get_slot_from_name (const char *name)
|
||||||
|
@ -540,10 +550,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
|
* __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
|
||||||
* @bus: bus this slot is on
|
* @bus: bus this slot is on
|
||||||
* @slot: pointer to the &struct hotplug_slot to register
|
* @slot: pointer to the &struct hotplug_slot to register
|
||||||
* @slot_nr: slot number
|
* @devnr: device number
|
||||||
* @name: name registered with kobject core
|
* @name: name registered with kobject core
|
||||||
*
|
*
|
||||||
* Registers a hotplug slot with the pci hotplug subsystem, which will allow
|
* Registers a hotplug slot with the pci hotplug subsystem, which will allow
|
||||||
|
@ -551,8 +561,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
|
||||||
*
|
*
|
||||||
* Returns 0 if successful, anything else for an error.
|
* Returns 0 if successful, anything else for an error.
|
||||||
*/
|
*/
|
||||||
int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
|
int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
|
||||||
const char *name)
|
int devnr, const char *name,
|
||||||
|
struct module *owner, const char *mod_name)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct pci_slot *pci_slot;
|
struct pci_slot *pci_slot;
|
||||||
|
@ -567,14 +578,16 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&pci_hp_mutex);
|
slot->ops->owner = owner;
|
||||||
|
slot->ops->mod_name = mod_name;
|
||||||
|
|
||||||
|
mutex_lock(&pci_hp_mutex);
|
||||||
/*
|
/*
|
||||||
* No problems if we call this interface from both ACPI_PCI_SLOT
|
* No problems if we call this interface from both ACPI_PCI_SLOT
|
||||||
* driver and call it here again. If we've already created the
|
* driver and call it here again. If we've already created the
|
||||||
* pci_slot, the interface will simply bump the refcount.
|
* pci_slot, the interface will simply bump the refcount.
|
||||||
*/
|
*/
|
||||||
pci_slot = pci_create_slot(bus, slot_nr, name, slot);
|
pci_slot = pci_create_slot(bus, devnr, name, slot);
|
||||||
if (IS_ERR(pci_slot)) {
|
if (IS_ERR(pci_slot)) {
|
||||||
result = PTR_ERR(pci_slot);
|
result = PTR_ERR(pci_slot);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -684,6 +697,6 @@ MODULE_LICENSE("GPL");
|
||||||
module_param(debug, bool, 0644);
|
module_param(debug, bool, 0644);
|
||||||
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
|
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(pci_hp_register);
|
EXPORT_SYMBOL_GPL(__pci_hp_register);
|
||||||
EXPORT_SYMBOL_GPL(pci_hp_deregister);
|
EXPORT_SYMBOL_GPL(pci_hp_deregister);
|
||||||
EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
|
EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
|
||||||
|
|
|
@ -81,7 +81,6 @@ struct slot {
|
||||||
struct hpc_ops *hpc_ops;
|
struct hpc_ops *hpc_ops;
|
||||||
struct hotplug_slot *hotplug_slot;
|
struct hotplug_slot *hotplug_slot;
|
||||||
struct list_head slot_list;
|
struct list_head slot_list;
|
||||||
unsigned long last_emi_toggle;
|
|
||||||
struct delayed_work work; /* work for button event */
|
struct delayed_work work; /* work for button event */
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
};
|
};
|
||||||
|
@ -203,8 +202,6 @@ struct hpc_ops {
|
||||||
int (*set_attention_status)(struct slot *slot, u8 status);
|
int (*set_attention_status)(struct slot *slot, u8 status);
|
||||||
int (*get_latch_status)(struct slot *slot, u8 *status);
|
int (*get_latch_status)(struct slot *slot, u8 *status);
|
||||||
int (*get_adapter_status)(struct slot *slot, u8 *status);
|
int (*get_adapter_status)(struct slot *slot, u8 *status);
|
||||||
int (*get_emi_status)(struct slot *slot, u8 *status);
|
|
||||||
int (*toggle_emi)(struct slot *slot);
|
|
||||||
int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
|
int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
|
||||||
int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
|
int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
|
||||||
int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
|
int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
|
||||||
|
|
|
@ -73,7 +73,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val
|
||||||
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
|
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
|
static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
|
@ -85,99 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
|
||||||
.get_cur_bus_speed = get_cur_bus_speed,
|
.get_cur_bus_speed = get_cur_bus_speed,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the status of the Electro Mechanical Interlock (EMI)
|
|
||||||
*/
|
|
||||||
static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
|
||||||
{
|
|
||||||
struct slot *slot = hotplug_slot->private;
|
|
||||||
return (slot->hpc_ops->get_emi_status(slot, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sysfs interface for the Electro Mechanical Interlock (EMI)
|
|
||||||
* 1 == locked, 0 == unlocked
|
|
||||||
*/
|
|
||||||
static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
u8 value;
|
|
||||||
|
|
||||||
retval = get_lock_status(slot, &value);
|
|
||||||
if (retval)
|
|
||||||
goto lock_read_exit;
|
|
||||||
retval = sprintf (buf, "%d\n", value);
|
|
||||||
|
|
||||||
lock_read_exit:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change the status of the Electro Mechanical Interlock (EMI)
|
|
||||||
* This is a toggle - in addition there must be at least 1 second
|
|
||||||
* in between toggles.
|
|
||||||
*/
|
|
||||||
static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
|
|
||||||
{
|
|
||||||
struct slot *slot = hotplug_slot->private;
|
|
||||||
int retval;
|
|
||||||
u8 value;
|
|
||||||
|
|
||||||
mutex_lock(&slot->ctrl->crit_sect);
|
|
||||||
|
|
||||||
/* has it been >1 sec since our last toggle? */
|
|
||||||
if ((get_seconds() - slot->last_emi_toggle) < 1) {
|
|
||||||
mutex_unlock(&slot->ctrl->crit_sect);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see what our current state is */
|
|
||||||
retval = get_lock_status(hotplug_slot, &value);
|
|
||||||
if (retval || (value == status))
|
|
||||||
goto set_lock_exit;
|
|
||||||
|
|
||||||
slot->hpc_ops->toggle_emi(slot);
|
|
||||||
set_lock_exit:
|
|
||||||
mutex_unlock(&slot->ctrl->crit_sect);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sysfs interface which allows the user to toggle the Electro Mechanical
|
|
||||||
* Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
|
|
||||||
*/
|
|
||||||
static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
struct slot *slot = hotplug_slot->private;
|
|
||||||
unsigned long llock;
|
|
||||||
u8 lock;
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
llock = simple_strtoul(buf, NULL, 10);
|
|
||||||
lock = (u8)(llock & 0xff);
|
|
||||||
|
|
||||||
switch (lock) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
retval = set_lock_status(hotplug_slot, lock);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ctrl_err(slot->ctrl, "%d is an invalid lock value\n",
|
|
||||||
lock);
|
|
||||||
retval = -EINVAL;
|
|
||||||
}
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
|
|
||||||
.attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
|
|
||||||
.show = lock_read_file,
|
|
||||||
.store = lock_write_file
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* release_slot - free up the memory used by a slot
|
* release_slot - free up the memory used by a slot
|
||||||
* @hotplug_slot: slot to free
|
* @hotplug_slot: slot to free
|
||||||
|
@ -236,17 +142,6 @@ static int init_slots(struct controller *ctrl)
|
||||||
get_attention_status(hotplug_slot, &info->attention_status);
|
get_attention_status(hotplug_slot, &info->attention_status);
|
||||||
get_latch_status(hotplug_slot, &info->latch_status);
|
get_latch_status(hotplug_slot, &info->latch_status);
|
||||||
get_adapter_status(hotplug_slot, &info->adapter_status);
|
get_adapter_status(hotplug_slot, &info->adapter_status);
|
||||||
/* create additional sysfs entries */
|
|
||||||
if (EMI(ctrl)) {
|
|
||||||
retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
|
|
||||||
&hotplug_slot_attr_lock.attr);
|
|
||||||
if (retval) {
|
|
||||||
pci_hp_deregister(hotplug_slot);
|
|
||||||
ctrl_err(ctrl, "Cannot create additional sysfs "
|
|
||||||
"entries\n");
|
|
||||||
goto error_info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -261,13 +156,8 @@ static int init_slots(struct controller *ctrl)
|
||||||
static void cleanup_slots(struct controller *ctrl)
|
static void cleanup_slots(struct controller *ctrl)
|
||||||
{
|
{
|
||||||
struct slot *slot;
|
struct slot *slot;
|
||||||
|
list_for_each_entry(slot, &ctrl->slot_list, slot_list)
|
||||||
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
|
|
||||||
if (EMI(ctrl))
|
|
||||||
sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
|
|
||||||
&hotplug_slot_attr_lock.attr);
|
|
||||||
pci_hp_deregister(slot->hotplug_slot);
|
pci_hp_deregister(slot->hotplug_slot);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot)
|
||||||
return !!(slot_status & PCI_EXP_SLTSTA_PFD);
|
return !!(slot_status & PCI_EXP_SLTSTA_PFD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpc_get_emi_status(struct slot *slot, u8 *status)
|
|
||||||
{
|
|
||||||
struct controller *ctrl = slot->ctrl;
|
|
||||||
u16 slot_status;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
|
|
||||||
if (retval) {
|
|
||||||
ctrl_err(ctrl, "Cannot check EMI status\n");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
*status = !!(slot_status & PCI_EXP_SLTSTA_EIS);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hpc_toggle_emi(struct slot *slot)
|
|
||||||
{
|
|
||||||
u16 slot_cmd;
|
|
||||||
u16 cmd_mask;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
slot_cmd = PCI_EXP_SLTCTL_EIC;
|
|
||||||
cmd_mask = PCI_EXP_SLTCTL_EIC;
|
|
||||||
rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
|
|
||||||
slot->last_emi_toggle = get_seconds();
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hpc_set_attention_status(struct slot *slot, u8 value)
|
static int hpc_set_attention_status(struct slot *slot, u8 value)
|
||||||
{
|
{
|
||||||
struct controller *ctrl = slot->ctrl;
|
struct controller *ctrl = slot->ctrl;
|
||||||
|
@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = {
|
||||||
.get_attention_status = hpc_get_attention_status,
|
.get_attention_status = hpc_get_attention_status,
|
||||||
.get_latch_status = hpc_get_latch_status,
|
.get_latch_status = hpc_get_latch_status,
|
||||||
.get_adapter_status = hpc_get_adapter_status,
|
.get_adapter_status = hpc_get_adapter_status,
|
||||||
.get_emi_status = hpc_get_emi_status,
|
|
||||||
.toggle_emi = hpc_toggle_emi,
|
|
||||||
|
|
||||||
.get_max_bus_speed = hpc_get_max_lnk_speed,
|
.get_max_bus_speed = hpc_get_max_lnk_speed,
|
||||||
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
|
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
|
||||||
|
|
|
@ -82,7 +82,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value);
|
||||||
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
|
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops skel_hotplug_slot_ops = {
|
static struct hotplug_slot_ops skel_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
|
|
|
@ -423,7 +423,6 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
|
struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
|
|
|
@ -83,7 +83,6 @@ static int disable_slot(struct hotplug_slot *slot);
|
||||||
static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
|
static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops sn_hotplug_slot_ops = {
|
static struct hotplug_slot_ops sn_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
.get_power_status = get_power_status,
|
.get_power_status = get_power_status,
|
||||||
|
|
|
@ -69,7 +69,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val
|
||||||
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
|
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
|
||||||
|
|
||||||
static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
|
static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.set_attention_status = set_attention_status,
|
.set_attention_status = set_attention_status,
|
||||||
.enable_slot = enable_slot,
|
.enable_slot = enable_slot,
|
||||||
.disable_slot = disable_slot,
|
.disable_slot = disable_slot,
|
||||||
|
|
|
@ -110,7 +110,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reset)
|
if (reset)
|
||||||
pci_execute_reset_function(virtfn);
|
__pci_reset_function(virtfn);
|
||||||
|
|
||||||
pci_device_add(virtfn, virtfn->bus);
|
pci_device_add(virtfn, virtfn->bus);
|
||||||
mutex_unlock(&iov->dev->sriov->lock);
|
mutex_unlock(&iov->dev->sriov->lock);
|
||||||
|
@ -164,7 +164,7 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
|
||||||
|
|
||||||
if (reset) {
|
if (reset) {
|
||||||
device_release_driver(&virtfn->dev);
|
device_release_driver(&virtfn->dev);
|
||||||
pci_execute_reset_function(virtfn);
|
__pci_reset_function(virtfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf, "virtfn%u", id);
|
sprintf(buf, "virtfn%u", id);
|
||||||
|
@ -487,6 +487,8 @@ static int sriov_init(struct pci_dev *dev, int pos)
|
||||||
iov->self = dev;
|
iov->self = dev;
|
||||||
pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
|
pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
|
||||||
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
|
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
|
||||||
|
if (dev->pcie_type == PCI_EXP_TYPE_RC_END)
|
||||||
|
iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
|
||||||
|
|
||||||
if (pdev)
|
if (pdev)
|
||||||
iov->dev = pci_dev_get(pdev);
|
iov->dev = pci_dev_get(pdev);
|
||||||
|
|
|
@ -75,22 +75,17 @@ void arch_teardown_msi_irqs(struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void __msi_set_enable(struct pci_dev *dev, int pos, int enable)
|
static void msi_set_enable(struct pci_dev *dev, int pos, int enable)
|
||||||
{
|
{
|
||||||
u16 control;
|
u16 control;
|
||||||
|
|
||||||
if (pos) {
|
BUG_ON(!pos);
|
||||||
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
|
|
||||||
control &= ~PCI_MSI_FLAGS_ENABLE;
|
|
||||||
if (enable)
|
|
||||||
control |= PCI_MSI_FLAGS_ENABLE;
|
|
||||||
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msi_set_enable(struct pci_dev *dev, int enable)
|
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
|
||||||
{
|
control &= ~PCI_MSI_FLAGS_ENABLE;
|
||||||
__msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable);
|
if (enable)
|
||||||
|
control |= PCI_MSI_FLAGS_ENABLE;
|
||||||
|
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msix_set_enable(struct pci_dev *dev, int enable)
|
static void msix_set_enable(struct pci_dev *dev, int enable)
|
||||||
|
@ -131,9 +126,6 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
|
||||||
* mask all MSI interrupts by clearing the MSI enable bit does not work
|
* mask all MSI interrupts by clearing the MSI enable bit does not work
|
||||||
* reliably as devices without an INTx disable bit will then generate a
|
* reliably as devices without an INTx disable bit will then generate a
|
||||||
* level IRQ which will never be cleared.
|
* level IRQ which will never be cleared.
|
||||||
*
|
|
||||||
* Returns 1 if it succeeded in masking the interrupt and 0 if the device
|
|
||||||
* doesn't support MSI masking.
|
|
||||||
*/
|
*/
|
||||||
static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||||
{
|
{
|
||||||
|
@ -303,7 +295,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
|
||||||
pos = entry->msi_attrib.pos;
|
pos = entry->msi_attrib.pos;
|
||||||
|
|
||||||
pci_intx_for_msi(dev, 0);
|
pci_intx_for_msi(dev, 0);
|
||||||
msi_set_enable(dev, 0);
|
msi_set_enable(dev, pos, 0);
|
||||||
write_msi_msg(dev->irq, &entry->msg);
|
write_msi_msg(dev->irq, &entry->msg);
|
||||||
|
|
||||||
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
|
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
|
||||||
|
@ -321,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
|
||||||
|
|
||||||
if (!dev->msix_enabled)
|
if (!dev->msix_enabled)
|
||||||
return;
|
return;
|
||||||
|
BUG_ON(list_empty(&dev->msi_list));
|
||||||
|
entry = list_entry(dev->msi_list.next, struct msi_desc, list);
|
||||||
|
pos = entry->msi_attrib.pos;
|
||||||
|
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
|
||||||
|
|
||||||
/* route the table */
|
/* route the table */
|
||||||
pci_intx_for_msi(dev, 0);
|
pci_intx_for_msi(dev, 0);
|
||||||
msix_set_enable(dev, 0);
|
control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
|
||||||
|
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
||||||
|
|
||||||
list_for_each_entry(entry, &dev->msi_list, list) {
|
list_for_each_entry(entry, &dev->msi_list, list) {
|
||||||
write_msi_msg(entry->irq, &entry->msg);
|
write_msi_msg(entry->irq, &entry->msg);
|
||||||
msix_mask_irq(entry, entry->masked);
|
msix_mask_irq(entry, entry->masked);
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(list_empty(&dev->msi_list));
|
|
||||||
entry = list_entry(dev->msi_list.next, struct msi_desc, list);
|
|
||||||
pos = entry->msi_attrib.pos;
|
|
||||||
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
|
|
||||||
control &= ~PCI_MSIX_FLAGS_MASKALL;
|
control &= ~PCI_MSIX_FLAGS_MASKALL;
|
||||||
control |= PCI_MSIX_FLAGS_ENABLE;
|
|
||||||
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,9 +357,9 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
|
||||||
u16 control;
|
u16 control;
|
||||||
unsigned mask;
|
unsigned mask;
|
||||||
|
|
||||||
msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
|
|
||||||
|
|
||||||
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
|
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
|
||||||
|
msi_set_enable(dev, pos, 0); /* Disable MSI during set up */
|
||||||
|
|
||||||
pci_read_config_word(dev, msi_control_reg(pos), &control);
|
pci_read_config_word(dev, msi_control_reg(pos), &control);
|
||||||
/* MSI Entry Initialization */
|
/* MSI Entry Initialization */
|
||||||
entry = alloc_msi_entry(dev);
|
entry = alloc_msi_entry(dev);
|
||||||
|
@ -381,7 +373,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
|
||||||
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
|
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
|
||||||
entry->msi_attrib.pos = pos;
|
entry->msi_attrib.pos = pos;
|
||||||
|
|
||||||
entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
|
entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64);
|
||||||
/* All MSIs are unmasked by default, Mask them all */
|
/* All MSIs are unmasked by default, Mask them all */
|
||||||
if (entry->msi_attrib.maskbit)
|
if (entry->msi_attrib.maskbit)
|
||||||
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
|
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
|
||||||
|
@ -399,7 +391,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
|
||||||
|
|
||||||
/* Set MSI enabled bits */
|
/* Set MSI enabled bits */
|
||||||
pci_intx_for_msi(dev, 0);
|
pci_intx_for_msi(dev, 0);
|
||||||
msi_set_enable(dev, 1);
|
msi_set_enable(dev, pos, 1);
|
||||||
dev->msi_enabled = 1;
|
dev->msi_enabled = 1;
|
||||||
|
|
||||||
dev->irq = entry->irq;
|
dev->irq = entry->irq;
|
||||||
|
@ -427,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev,
|
||||||
u8 bir;
|
u8 bir;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
|
||||||
msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
|
|
||||||
|
|
||||||
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
||||||
|
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
|
||||||
|
|
||||||
|
/* Ensure MSI-X is disabled while it is set up */
|
||||||
|
control &= ~PCI_MSIX_FLAGS_ENABLE;
|
||||||
|
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
||||||
|
|
||||||
/* Request & Map MSI-X table region */
|
/* Request & Map MSI-X table region */
|
||||||
pci_read_config_word(dev, msi_control_reg(pos), &control);
|
|
||||||
nr_entries = multi_msix_capable(control);
|
nr_entries = multi_msix_capable(control);
|
||||||
|
|
||||||
pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
|
pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
|
||||||
|
@ -442,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev,
|
||||||
if (base == NULL)
|
if (base == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* MSI-X Table Initialization */
|
|
||||||
for (i = 0; i < nvec; i++) {
|
for (i = 0; i < nvec; i++) {
|
||||||
entry = alloc_msi_entry(dev);
|
entry = alloc_msi_entry(dev);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
|
@ -455,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev,
|
||||||
entry->msi_attrib.default_irq = dev->irq;
|
entry->msi_attrib.default_irq = dev->irq;
|
||||||
entry->msi_attrib.pos = pos;
|
entry->msi_attrib.pos = pos;
|
||||||
entry->mask_base = base;
|
entry->mask_base = base;
|
||||||
msix_mask_irq(entry, 1);
|
|
||||||
|
|
||||||
list_add_tail(&entry->list, &dev->msi_list);
|
list_add_tail(&entry->list, &dev->msi_list);
|
||||||
}
|
}
|
||||||
|
@ -480,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some devices require MSI-X to be enabled before we can touch the
|
||||||
|
* MSI-X registers. We need to mask all the vectors to prevent
|
||||||
|
* interrupts coming in before they're fully set up.
|
||||||
|
*/
|
||||||
|
control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
|
||||||
|
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
list_for_each_entry(entry, &dev->msi_list, list) {
|
list_for_each_entry(entry, &dev->msi_list, list) {
|
||||||
entries[i].vector = entry->irq;
|
entries[i].vector = entry->irq;
|
||||||
set_irq_msi(entry->irq, entry);
|
set_irq_msi(entry->irq, entry);
|
||||||
|
j = entries[i].entry;
|
||||||
|
entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
|
||||||
|
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
|
||||||
|
msix_mask_irq(entry, 1);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
/* Set MSI-X enabled bits */
|
|
||||||
|
/* Set MSI-X enabled bits and unmask the function */
|
||||||
pci_intx_for_msi(dev, 0);
|
pci_intx_for_msi(dev, 0);
|
||||||
msix_set_enable(dev, 1);
|
|
||||||
dev->msix_enabled = 1;
|
dev->msix_enabled = 1;
|
||||||
|
|
||||||
list_for_each_entry(entry, &dev->msi_list, list) {
|
control &= ~PCI_MSIX_FLAGS_MASKALL;
|
||||||
int vector = entry->msi_attrib.entry_nr;
|
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
|
||||||
entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE +
|
|
||||||
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -596,17 +598,20 @@ void pci_msi_shutdown(struct pci_dev *dev)
|
||||||
struct msi_desc *desc;
|
struct msi_desc *desc;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
|
unsigned pos;
|
||||||
|
|
||||||
if (!pci_msi_enable || !dev || !dev->msi_enabled)
|
if (!pci_msi_enable || !dev || !dev->msi_enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
msi_set_enable(dev, 0);
|
BUG_ON(list_empty(&dev->msi_list));
|
||||||
|
desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
|
||||||
|
pos = desc->msi_attrib.pos;
|
||||||
|
|
||||||
|
msi_set_enable(dev, pos, 0);
|
||||||
pci_intx_for_msi(dev, 1);
|
pci_intx_for_msi(dev, 1);
|
||||||
dev->msi_enabled = 0;
|
dev->msi_enabled = 0;
|
||||||
|
|
||||||
BUG_ON(list_empty(&dev->msi_list));
|
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
|
||||||
desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
|
|
||||||
pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
|
|
||||||
mask = msi_capable_mask(ctrl);
|
mask = msi_capable_mask(ctrl);
|
||||||
msi_mask_irq(desc, mask, ~mask);
|
msi_mask_irq(desc, mask, ~mask);
|
||||||
|
|
||||||
|
@ -648,10 +653,7 @@ static int msi_free_irqs(struct pci_dev* dev)
|
||||||
|
|
||||||
list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
|
list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
|
||||||
if (entry->msi_attrib.is_msix) {
|
if (entry->msi_attrib.is_msix) {
|
||||||
writel(1, entry->mask_base + entry->msi_attrib.entry_nr
|
msix_mask_irq(entry, 1);
|
||||||
* PCI_MSIX_ENTRY_SIZE
|
|
||||||
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
|
|
||||||
|
|
||||||
if (list_is_last(&entry->list, &dev->msi_list))
|
if (list_is_last(&entry->list, &dev->msi_list))
|
||||||
iounmap(entry->mask_base);
|
iounmap(entry->mask_base);
|
||||||
}
|
}
|
||||||
|
@ -691,8 +693,8 @@ int pci_msix_table_size(struct pci_dev *dev)
|
||||||
* indicates the successful configuration of MSI-X capability structure
|
* indicates the successful configuration of MSI-X capability structure
|
||||||
* with new allocated MSI-X irqs. A return of < 0 indicates a failure.
|
* with new allocated MSI-X irqs. A return of < 0 indicates a failure.
|
||||||
* Or a return of > 0 indicates that driver request is exceeding the number
|
* Or a return of > 0 indicates that driver request is exceeding the number
|
||||||
* of irqs available. Driver should use the returned value to re-send
|
* of irqs or MSI-X vectors available. Driver should use the returned value to
|
||||||
* its request.
|
* re-send its request.
|
||||||
**/
|
**/
|
||||||
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
|
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
|
||||||
{
|
{
|
||||||
|
@ -708,7 +710,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
|
||||||
|
|
||||||
nr_entries = pci_msix_table_size(dev);
|
nr_entries = pci_msix_table_size(dev);
|
||||||
if (nvec > nr_entries)
|
if (nvec > nr_entries)
|
||||||
return -EINVAL;
|
return nr_entries;
|
||||||
|
|
||||||
/* Check for any invalid entries */
|
/* Check for any invalid entries */
|
||||||
for (i = 0; i < nvec; i++) {
|
for (i = 0; i < nvec; i++) {
|
||||||
|
|
|
@ -16,21 +16,15 @@
|
||||||
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
|
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
|
||||||
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
|
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
|
||||||
#define msi_data_reg(base, is64bit) \
|
#define msi_data_reg(base, is64bit) \
|
||||||
( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
|
(base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32))
|
||||||
#define msi_mask_bits_reg(base, is64bit) \
|
#define msi_mask_reg(base, is64bit) \
|
||||||
( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
|
(base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
|
||||||
#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE
|
|
||||||
#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
|
#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
|
||||||
#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
|
#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
|
||||||
|
|
||||||
#define msix_table_offset_reg(base) (base + 0x04)
|
#define msix_table_offset_reg(base) (base + 0x04)
|
||||||
#define msix_pba_offset_reg(base) (base + 0x08)
|
#define msix_pba_offset_reg(base) (base + 0x08)
|
||||||
#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
|
|
||||||
#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE
|
|
||||||
#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
|
#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
|
||||||
#define multi_msix_capable msix_table_size
|
#define multi_msix_capable(control) msix_table_size((control))
|
||||||
#define msix_unmask(address) (address & ~PCI_MSIX_FLAGS_BITMASK)
|
|
||||||
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
|
|
||||||
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
|
|
||||||
|
|
||||||
#endif /* MSI_H */
|
#endif /* MSI_H */
|
||||||
|
|
|
@ -485,6 +485,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||||
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
|
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||||
pmcsr |= state;
|
pmcsr |= state;
|
||||||
break;
|
break;
|
||||||
|
case PCI_D3hot:
|
||||||
|
case PCI_D3cold:
|
||||||
case PCI_UNKNOWN: /* Boot-up */
|
case PCI_UNKNOWN: /* Boot-up */
|
||||||
if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
|
if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
|
||||||
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
|
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
|
||||||
|
@ -1208,7 +1210,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
|
||||||
* Error code depending on the platform is returned if both the platform and
|
* Error code depending on the platform is returned if both the platform and
|
||||||
* the native mechanism fail to enable the generation of wake-up events
|
* the native mechanism fail to enable the generation of wake-up events
|
||||||
*/
|
*/
|
||||||
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
|
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
bool pme_done = false;
|
bool pme_done = false;
|
||||||
|
@ -1287,15 +1289,14 @@ pci_power_t pci_target_state(struct pci_dev *dev)
|
||||||
default:
|
default:
|
||||||
target_state = state;
|
target_state = state;
|
||||||
}
|
}
|
||||||
|
} else if (!dev->pm_cap) {
|
||||||
|
target_state = PCI_D0;
|
||||||
} else if (device_may_wakeup(&dev->dev)) {
|
} else if (device_may_wakeup(&dev->dev)) {
|
||||||
/*
|
/*
|
||||||
* Find the deepest state from which the device can generate
|
* Find the deepest state from which the device can generate
|
||||||
* wake-up events, make it the target state and enable device
|
* wake-up events, make it the target state and enable device
|
||||||
* to generate PME#.
|
* to generate PME#.
|
||||||
*/
|
*/
|
||||||
if (!dev->pm_cap)
|
|
||||||
return PCI_POWER_ERROR;
|
|
||||||
|
|
||||||
if (dev->pme_support) {
|
if (dev->pme_support) {
|
||||||
while (target_state
|
while (target_state
|
||||||
&& !(dev->pme_support & (1 << target_state)))
|
&& !(dev->pme_support & (1 << target_state)))
|
||||||
|
@ -1532,7 +1533,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
|
||||||
if (!pin)
|
if (!pin)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (dev->bus->parent) {
|
while (!pci_is_root_bus(dev->bus)) {
|
||||||
pin = pci_swizzle_interrupt_pin(dev, pin);
|
pin = pci_swizzle_interrupt_pin(dev, pin);
|
||||||
dev = dev->bus->self;
|
dev = dev->bus->self;
|
||||||
}
|
}
|
||||||
|
@ -1552,7 +1553,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
|
||||||
{
|
{
|
||||||
u8 pin = *pinp;
|
u8 pin = *pinp;
|
||||||
|
|
||||||
while (dev->bus->parent) {
|
while (!pci_is_root_bus(dev->bus)) {
|
||||||
pin = pci_swizzle_interrupt_pin(dev, pin);
|
pin = pci_swizzle_interrupt_pin(dev, pin);
|
||||||
dev = dev->bus->self;
|
dev = dev->bus->self;
|
||||||
}
|
}
|
||||||
|
@ -2058,111 +2059,177 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
|
||||||
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
|
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int __pcie_flr(struct pci_dev *dev, int probe)
|
static int pcie_flr(struct pci_dev *dev, int probe)
|
||||||
{
|
{
|
||||||
u16 status;
|
int i;
|
||||||
|
int pos;
|
||||||
u32 cap;
|
u32 cap;
|
||||||
int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
u16 status;
|
||||||
|
|
||||||
if (!exppos)
|
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||||
|
if (!pos)
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap);
|
|
||||||
|
pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
|
||||||
if (!(cap & PCI_EXP_DEVCAP_FLR))
|
if (!(cap & PCI_EXP_DEVCAP_FLR))
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
||||||
if (probe)
|
if (probe)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pci_block_user_cfg_access(dev);
|
|
||||||
|
|
||||||
/* Wait for Transaction Pending bit clean */
|
/* Wait for Transaction Pending bit clean */
|
||||||
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
|
for (i = 0; i < 4; i++) {
|
||||||
if (!(status & PCI_EXP_DEVSTA_TRPND))
|
if (i)
|
||||||
goto transaction_done;
|
msleep((1 << (i - 1)) * 100);
|
||||||
|
|
||||||
msleep(100);
|
pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
|
||||||
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
|
if (!(status & PCI_EXP_DEVSTA_TRPND))
|
||||||
if (!(status & PCI_EXP_DEVSTA_TRPND))
|
goto clear;
|
||||||
goto transaction_done;
|
}
|
||||||
|
|
||||||
dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
|
dev_err(&dev->dev, "transaction is not cleared; "
|
||||||
"sleeping for 1 second\n");
|
"proceeding with reset anyway\n");
|
||||||
ssleep(1);
|
|
||||||
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
|
|
||||||
if (status & PCI_EXP_DEVSTA_TRPND)
|
|
||||||
dev_info(&dev->dev, "Still busy after 1s; "
|
|
||||||
"proceeding with reset anyway\n");
|
|
||||||
|
|
||||||
transaction_done:
|
clear:
|
||||||
pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL,
|
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
|
||||||
PCI_EXP_DEVCTL_BCR_FLR);
|
PCI_EXP_DEVCTL_BCR_FLR);
|
||||||
mdelay(100);
|
msleep(100);
|
||||||
|
|
||||||
pci_unblock_user_cfg_access(dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __pci_af_flr(struct pci_dev *dev, int probe)
|
static int pci_af_flr(struct pci_dev *dev, int probe)
|
||||||
{
|
{
|
||||||
int cappos = pci_find_capability(dev, PCI_CAP_ID_AF);
|
int i;
|
||||||
u8 status;
|
int pos;
|
||||||
u8 cap;
|
u8 cap;
|
||||||
|
u8 status;
|
||||||
|
|
||||||
if (!cappos)
|
pos = pci_find_capability(dev, PCI_CAP_ID_AF);
|
||||||
|
if (!pos)
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap);
|
|
||||||
|
pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap);
|
||||||
if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR))
|
if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR))
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
||||||
if (probe)
|
if (probe)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pci_block_user_cfg_access(dev);
|
|
||||||
|
|
||||||
/* Wait for Transaction Pending bit clean */
|
/* Wait for Transaction Pending bit clean */
|
||||||
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
|
for (i = 0; i < 4; i++) {
|
||||||
if (!(status & PCI_AF_STATUS_TP))
|
if (i)
|
||||||
goto transaction_done;
|
msleep((1 << (i - 1)) * 100);
|
||||||
|
|
||||||
|
pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status);
|
||||||
|
if (!(status & PCI_AF_STATUS_TP))
|
||||||
|
goto clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&dev->dev, "transaction is not cleared; "
|
||||||
|
"proceeding with reset anyway\n");
|
||||||
|
|
||||||
|
clear:
|
||||||
|
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
|
||||||
msleep(100);
|
msleep(100);
|
||||||
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
|
|
||||||
if (!(status & PCI_AF_STATUS_TP))
|
|
||||||
goto transaction_done;
|
|
||||||
|
|
||||||
dev_info(&dev->dev, "Busy after 100ms while trying to"
|
|
||||||
" reset; sleeping for 1 second\n");
|
|
||||||
ssleep(1);
|
|
||||||
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
|
|
||||||
if (status & PCI_AF_STATUS_TP)
|
|
||||||
dev_info(&dev->dev, "Still busy after 1s; "
|
|
||||||
"proceeding with reset anyway\n");
|
|
||||||
|
|
||||||
transaction_done:
|
|
||||||
pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
|
|
||||||
mdelay(100);
|
|
||||||
|
|
||||||
pci_unblock_user_cfg_access(dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __pci_reset_function(struct pci_dev *pdev, int probe)
|
static int pci_pm_reset(struct pci_dev *dev, int probe)
|
||||||
{
|
{
|
||||||
int res;
|
u16 csr;
|
||||||
|
|
||||||
res = __pcie_flr(pdev, probe);
|
if (!dev->pm_cap)
|
||||||
if (res != -ENOTTY)
|
return -ENOTTY;
|
||||||
return res;
|
|
||||||
|
|
||||||
res = __pci_af_flr(pdev, probe);
|
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
|
||||||
if (res != -ENOTTY)
|
if (csr & PCI_PM_CTRL_NO_SOFT_RESET)
|
||||||
return res;
|
return -ENOTTY;
|
||||||
|
|
||||||
return res;
|
if (probe)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dev->current_state != PCI_D0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
csr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||||
|
csr |= PCI_D3hot;
|
||||||
|
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
|
||||||
|
msleep(pci_pm_d3_delay);
|
||||||
|
|
||||||
|
csr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||||
|
csr |= PCI_D0;
|
||||||
|
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
|
||||||
|
msleep(pci_pm_d3_delay);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
|
||||||
|
{
|
||||||
|
u16 ctrl;
|
||||||
|
struct pci_dev *pdev;
|
||||||
|
|
||||||
|
if (dev->subordinate)
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
|
list_for_each_entry(pdev, &dev->bus->devices, bus_list)
|
||||||
|
if (pdev != dev)
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pci_dev_reset(struct pci_dev *dev, int probe)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
if (!probe) {
|
||||||
|
pci_block_user_cfg_access(dev);
|
||||||
|
/* block PM suspend, driver probe, etc. */
|
||||||
|
down(&dev->dev.sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = pcie_flr(dev, probe);
|
||||||
|
if (rc != -ENOTTY)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
rc = pci_af_flr(dev, probe);
|
||||||
|
if (rc != -ENOTTY)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
rc = pci_pm_reset(dev, probe);
|
||||||
|
if (rc != -ENOTTY)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
rc = pci_parent_bus_reset(dev, probe);
|
||||||
|
done:
|
||||||
|
if (!probe) {
|
||||||
|
up(&dev->dev.sem);
|
||||||
|
pci_unblock_user_cfg_access(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_execute_reset_function() - Reset a PCI device function
|
* __pci_reset_function - reset a PCI device function
|
||||||
* @dev: Device function to reset
|
* @dev: PCI device to reset
|
||||||
*
|
*
|
||||||
* Some devices allow an individual function to be reset without affecting
|
* Some devices allow an individual function to be reset without affecting
|
||||||
* other functions in the same device. The PCI device must be responsive
|
* other functions in the same device. The PCI device must be responsive
|
||||||
|
@ -2174,18 +2241,18 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe)
|
||||||
* device including MSI, bus mastering, BARs, decoding IO and memory spaces,
|
* device including MSI, bus mastering, BARs, decoding IO and memory spaces,
|
||||||
* etc.
|
* etc.
|
||||||
*
|
*
|
||||||
* Returns 0 if the device function was successfully reset or -ENOTTY if the
|
* Returns 0 if the device function was successfully reset or negative if the
|
||||||
* device doesn't support resetting a single function.
|
* device doesn't support resetting a single function.
|
||||||
*/
|
*/
|
||||||
int pci_execute_reset_function(struct pci_dev *dev)
|
int __pci_reset_function(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
return __pci_reset_function(dev, 0);
|
return pci_dev_reset(dev, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_execute_reset_function);
|
EXPORT_SYMBOL_GPL(__pci_reset_function);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_reset_function() - quiesce and reset a PCI device function
|
* pci_reset_function - quiesce and reset a PCI device function
|
||||||
* @dev: Device function to reset
|
* @dev: PCI device to reset
|
||||||
*
|
*
|
||||||
* Some devices allow an individual function to be reset without affecting
|
* Some devices allow an individual function to be reset without affecting
|
||||||
* other functions in the same device. The PCI device must be responsive
|
* other functions in the same device. The PCI device must be responsive
|
||||||
|
@ -2193,32 +2260,33 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function);
|
||||||
*
|
*
|
||||||
* This function does not just reset the PCI portion of a device, but
|
* This function does not just reset the PCI portion of a device, but
|
||||||
* clears all the state associated with the device. This function differs
|
* clears all the state associated with the device. This function differs
|
||||||
* from pci_execute_reset_function in that it saves and restores device state
|
* from __pci_reset_function in that it saves and restores device state
|
||||||
* over the reset.
|
* over the reset.
|
||||||
*
|
*
|
||||||
* Returns 0 if the device function was successfully reset or -ENOTTY if the
|
* Returns 0 if the device function was successfully reset or negative if the
|
||||||
* device doesn't support resetting a single function.
|
* device doesn't support resetting a single function.
|
||||||
*/
|
*/
|
||||||
int pci_reset_function(struct pci_dev *dev)
|
int pci_reset_function(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
int r = __pci_reset_function(dev, 1);
|
int rc;
|
||||||
|
|
||||||
if (r < 0)
|
rc = pci_dev_reset(dev, 1);
|
||||||
return r;
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0)
|
|
||||||
disable_irq(dev->irq);
|
|
||||||
pci_save_state(dev);
|
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_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
|
||||||
|
|
||||||
r = pci_execute_reset_function(dev);
|
rc = pci_dev_reset(dev, 0);
|
||||||
|
|
||||||
pci_restore_state(dev);
|
pci_restore_state(dev);
|
||||||
if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0)
|
|
||||||
enable_irq(dev->irq);
|
|
||||||
|
|
||||||
return r;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_reset_function);
|
EXPORT_SYMBOL_GPL(pci_reset_function);
|
||||||
|
|
||||||
|
@ -2591,6 +2659,8 @@ static int __init pci_setup(char *str)
|
||||||
} else if (!strncmp(str, "resource_alignment=", 19)) {
|
} else if (!strncmp(str, "resource_alignment=", 19)) {
|
||||||
pci_set_resource_alignment_param(str + 19,
|
pci_set_resource_alignment_param(str + 19,
|
||||||
strlen(str + 19));
|
strlen(str + 19));
|
||||||
|
} else if (!strncmp(str, "ecrc=", 5)) {
|
||||||
|
pcie_ecrc_get_policy(str + 5);
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_ERR "PCI: Unknown option `%s'\n",
|
printk(KERN_ERR "PCI: Unknown option `%s'\n",
|
||||||
str);
|
str);
|
||||||
|
|
|
@ -10,3 +10,18 @@ config PCIEAER
|
||||||
This enables PCI Express Root Port Advanced Error Reporting
|
This enables PCI Express Root Port Advanced Error Reporting
|
||||||
(AER) driver support. Error reporting messages sent to Root
|
(AER) driver support. Error reporting messages sent to Root
|
||||||
Port will be handled by PCI Express AER driver.
|
Port will be handled by PCI Express AER driver.
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# PCI Express ECRC
|
||||||
|
#
|
||||||
|
config PCIE_ECRC
|
||||||
|
bool "PCI Express ECRC settings control"
|
||||||
|
depends on PCIEAER
|
||||||
|
help
|
||||||
|
Used to override firmware/bios settings for PCI Express ECRC
|
||||||
|
(transaction layer end-to-end CRC checking).
|
||||||
|
|
||||||
|
When in doubt, say N.
|
||||||
|
|
||||||
|
source "drivers/pci/pcie/aer/Kconfig.debug"
|
||||||
|
|
18
drivers/pci/pcie/aer/Kconfig.debug
Normal file
18
drivers/pci/pcie/aer/Kconfig.debug
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
# PCI Express Root Port Device AER Debug Configuration
|
||||||
|
#
|
||||||
|
|
||||||
|
config PCIEAER_INJECT
|
||||||
|
tristate "PCIE AER error injector support"
|
||||||
|
depends on PCIEAER
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This enables PCI Express Root Port Advanced Error Reporting
|
||||||
|
(AER) software error injector.
|
||||||
|
|
||||||
|
Debuging PCIE AER code is quite difficult because it is hard
|
||||||
|
to trigger various real hardware errors. Software based
|
||||||
|
error injection can fake almost all kinds of errors with the
|
||||||
|
help of a user space helper tool aer-inject, which can be
|
||||||
|
gotten from:
|
||||||
|
http://www.kernel.org/pub/linux/utils/pci/aer-inject/
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
obj-$(CONFIG_PCIEAER) += aerdriver.o
|
obj-$(CONFIG_PCIEAER) += aerdriver.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_PCIE_ECRC) += ecrc.o
|
||||||
|
|
||||||
aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o
|
aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o
|
||||||
aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o
|
aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
|
||||||
|
|
473
drivers/pci/pcie/aer/aer_inject.c
Normal file
473
drivers/pci/pcie/aer/aer_inject.c
Normal file
|
@ -0,0 +1,473 @@
|
||||||
|
/*
|
||||||
|
* PCIE AER software error injection support.
|
||||||
|
*
|
||||||
|
* Debuging PCIE AER code is quite difficult because it is hard to
|
||||||
|
* trigger various real hardware errors. Software based error
|
||||||
|
* injection can fake almost all kinds of errors with the help of a
|
||||||
|
* user space helper tool aer-inject, which can be gotten from:
|
||||||
|
* http://www.kernel.org/pub/linux/utils/pci/aer-inject/
|
||||||
|
*
|
||||||
|
* Copyright 2009 Intel Corporation.
|
||||||
|
* Huang Ying <ying.huang@intel.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; version 2
|
||||||
|
* of the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include "aerdrv.h"
|
||||||
|
|
||||||
|
struct aer_error_inj
|
||||||
|
{
|
||||||
|
u8 bus;
|
||||||
|
u8 dev;
|
||||||
|
u8 fn;
|
||||||
|
u32 uncor_status;
|
||||||
|
u32 cor_status;
|
||||||
|
u32 header_log0;
|
||||||
|
u32 header_log1;
|
||||||
|
u32 header_log2;
|
||||||
|
u32 header_log3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aer_error
|
||||||
|
{
|
||||||
|
struct list_head list;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int devfn;
|
||||||
|
int pos_cap_err;
|
||||||
|
|
||||||
|
u32 uncor_status;
|
||||||
|
u32 cor_status;
|
||||||
|
u32 header_log0;
|
||||||
|
u32 header_log1;
|
||||||
|
u32 header_log2;
|
||||||
|
u32 header_log3;
|
||||||
|
u32 root_status;
|
||||||
|
u32 source_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pci_bus_ops
|
||||||
|
{
|
||||||
|
struct list_head list;
|
||||||
|
struct pci_bus *bus;
|
||||||
|
struct pci_ops *ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(einjected);
|
||||||
|
|
||||||
|
static LIST_HEAD(pci_bus_ops_list);
|
||||||
|
|
||||||
|
/* Protect einjected and pci_bus_ops_list */
|
||||||
|
static DEFINE_SPINLOCK(inject_lock);
|
||||||
|
|
||||||
|
static void aer_error_init(struct aer_error *err, unsigned int bus,
|
||||||
|
unsigned int devfn, int pos_cap_err)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&err->list);
|
||||||
|
err->bus = bus;
|
||||||
|
err->devfn = devfn;
|
||||||
|
err->pos_cap_err = pos_cap_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inject_lock must be held before calling */
|
||||||
|
static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn)
|
||||||
|
{
|
||||||
|
struct aer_error *err;
|
||||||
|
|
||||||
|
list_for_each_entry(err, &einjected, list) {
|
||||||
|
if (bus == err->bus && devfn == err->devfn)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inject_lock must be held before calling */
|
||||||
|
static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return __find_aer_error(dev->bus->number, dev->devfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inject_lock must be held before calling */
|
||||||
|
static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
struct pci_bus_ops *bus_ops;
|
||||||
|
|
||||||
|
list_for_each_entry(bus_ops, &pci_bus_ops_list, list) {
|
||||||
|
if (bus_ops->bus == bus)
|
||||||
|
return bus_ops->ops;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_bus_ops *pci_bus_ops_pop(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct pci_bus_ops *bus_ops = NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
if (list_empty(&pci_bus_ops_list))
|
||||||
|
bus_ops = NULL;
|
||||||
|
else {
|
||||||
|
struct list_head *lh = pci_bus_ops_list.next;
|
||||||
|
list_del(lh);
|
||||||
|
bus_ops = list_entry(lh, struct pci_bus_ops, list);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
return bus_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 *find_pci_config_dword(struct aer_error *err, int where,
|
||||||
|
int *prw1cs)
|
||||||
|
{
|
||||||
|
int rw1cs = 0;
|
||||||
|
u32 *target = NULL;
|
||||||
|
|
||||||
|
if (err->pos_cap_err == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch (where - err->pos_cap_err) {
|
||||||
|
case PCI_ERR_UNCOR_STATUS:
|
||||||
|
target = &err->uncor_status;
|
||||||
|
rw1cs = 1;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_COR_STATUS:
|
||||||
|
target = &err->cor_status;
|
||||||
|
rw1cs = 1;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_HEADER_LOG:
|
||||||
|
target = &err->header_log0;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_HEADER_LOG+4:
|
||||||
|
target = &err->header_log1;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_HEADER_LOG+8:
|
||||||
|
target = &err->header_log2;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_HEADER_LOG+12:
|
||||||
|
target = &err->header_log3;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_ROOT_STATUS:
|
||||||
|
target = &err->root_status;
|
||||||
|
rw1cs = 1;
|
||||||
|
break;
|
||||||
|
case PCI_ERR_ROOT_COR_SRC:
|
||||||
|
target = &err->source_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (prw1cs)
|
||||||
|
*prw1cs = rw1cs;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
|
||||||
|
int size, u32 *val)
|
||||||
|
{
|
||||||
|
u32 *sim;
|
||||||
|
struct aer_error *err;
|
||||||
|
unsigned long flags;
|
||||||
|
struct pci_ops *ops;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
if (size != sizeof(u32))
|
||||||
|
goto out;
|
||||||
|
err = __find_aer_error(bus->number, devfn);
|
||||||
|
if (!err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
sim = find_pci_config_dword(err, where, NULL);
|
||||||
|
if (sim) {
|
||||||
|
*val = *sim;
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
ops = __find_pci_bus_ops(bus);
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
return ops->read(bus, devfn, where, size, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
u32 *sim;
|
||||||
|
struct aer_error *err;
|
||||||
|
unsigned long flags;
|
||||||
|
int rw1cs;
|
||||||
|
struct pci_ops *ops;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
if (size != sizeof(u32))
|
||||||
|
goto out;
|
||||||
|
err = __find_aer_error(bus->number, devfn);
|
||||||
|
if (!err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
sim = find_pci_config_dword(err, where, &rw1cs);
|
||||||
|
if (sim) {
|
||||||
|
if (rw1cs)
|
||||||
|
*sim ^= val;
|
||||||
|
else
|
||||||
|
*sim = val;
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
ops = __find_pci_bus_ops(bus);
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
return ops->write(bus, devfn, where, size, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_ops pci_ops_aer = {
|
||||||
|
.read = pci_read_aer,
|
||||||
|
.write = pci_write_aer,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pci_bus_ops_init(struct pci_bus_ops *bus_ops,
|
||||||
|
struct pci_bus *bus,
|
||||||
|
struct pci_ops *ops)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&bus_ops->list);
|
||||||
|
bus_ops->bus = bus;
|
||||||
|
bus_ops->ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pci_bus_set_aer_ops(struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
struct pci_ops *ops;
|
||||||
|
struct pci_bus_ops *bus_ops;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL);
|
||||||
|
if (!bus_ops)
|
||||||
|
return -ENOMEM;
|
||||||
|
ops = pci_bus_set_ops(bus, &pci_ops_aer);
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
if (ops == &pci_ops_aer)
|
||||||
|
goto out;
|
||||||
|
pci_bus_ops_init(bus_ops, bus, ops);
|
||||||
|
list_add(&bus_ops->list, &pci_bus_ops_list);
|
||||||
|
bus_ops = NULL;
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
if (bus_ops)
|
||||||
|
kfree(bus_ops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
if (!dev->is_pcie)
|
||||||
|
break;
|
||||||
|
if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
|
||||||
|
return dev;
|
||||||
|
if (!dev->bus->self)
|
||||||
|
break;
|
||||||
|
dev = dev->bus->self;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_aer_device_iter(struct device *device, void *data)
|
||||||
|
{
|
||||||
|
struct pcie_device **result = data;
|
||||||
|
struct pcie_device *pcie_dev;
|
||||||
|
|
||||||
|
if (device->bus == &pcie_port_bus_type) {
|
||||||
|
pcie_dev = to_pcie_device(device);
|
||||||
|
if (pcie_dev->service & PCIE_PORT_SERVICE_AER) {
|
||||||
|
*result = pcie_dev;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_aer_device(struct pci_dev *dev, struct pcie_device **result)
|
||||||
|
{
|
||||||
|
return device_for_each_child(&dev->dev, result, find_aer_device_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aer_inject(struct aer_error_inj *einj)
|
||||||
|
{
|
||||||
|
struct aer_error *err, *rperr;
|
||||||
|
struct aer_error *err_alloc = NULL, *rperr_alloc = NULL;
|
||||||
|
struct pci_dev *dev, *rpdev;
|
||||||
|
struct pcie_device *edev;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
|
||||||
|
int pos_cap_err, rp_pos_cap_err;
|
||||||
|
u32 sever;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dev = pci_get_bus_and_slot(einj->bus, devfn);
|
||||||
|
if (!dev)
|
||||||
|
return -EINVAL;
|
||||||
|
rpdev = pcie_find_root_port(dev);
|
||||||
|
if (!rpdev) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!pos_cap_err) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
|
||||||
|
|
||||||
|
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!rp_pos_cap_err) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL);
|
||||||
|
if (!err_alloc) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
rperr_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL);
|
||||||
|
if (!rperr_alloc) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
|
||||||
|
err = __find_aer_error_by_dev(dev);
|
||||||
|
if (!err) {
|
||||||
|
err = err_alloc;
|
||||||
|
err_alloc = NULL;
|
||||||
|
aer_error_init(err, einj->bus, devfn, pos_cap_err);
|
||||||
|
list_add(&err->list, &einjected);
|
||||||
|
}
|
||||||
|
err->uncor_status |= einj->uncor_status;
|
||||||
|
err->cor_status |= einj->cor_status;
|
||||||
|
err->header_log0 = einj->header_log0;
|
||||||
|
err->header_log1 = einj->header_log1;
|
||||||
|
err->header_log2 = einj->header_log2;
|
||||||
|
err->header_log3 = einj->header_log3;
|
||||||
|
|
||||||
|
rperr = __find_aer_error_by_dev(rpdev);
|
||||||
|
if (!rperr) {
|
||||||
|
rperr = rperr_alloc;
|
||||||
|
rperr_alloc = NULL;
|
||||||
|
aer_error_init(rperr, rpdev->bus->number, rpdev->devfn,
|
||||||
|
rp_pos_cap_err);
|
||||||
|
list_add(&rperr->list, &einjected);
|
||||||
|
}
|
||||||
|
if (einj->cor_status) {
|
||||||
|
if (rperr->root_status & PCI_ERR_ROOT_COR_RCV)
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
|
||||||
|
else
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_COR_RCV;
|
||||||
|
rperr->source_id &= 0xffff0000;
|
||||||
|
rperr->source_id |= (einj->bus << 8) | devfn;
|
||||||
|
}
|
||||||
|
if (einj->uncor_status) {
|
||||||
|
if (rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV)
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
|
||||||
|
if (sever & einj->uncor_status) {
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_FATAL_RCV;
|
||||||
|
if (!(rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV))
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_FIRST_FATAL;
|
||||||
|
} else
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
|
||||||
|
rperr->root_status |= PCI_ERR_ROOT_UNCOR_RCV;
|
||||||
|
rperr->source_id &= 0x0000ffff;
|
||||||
|
rperr->source_id |= ((einj->bus << 8) | devfn) << 16;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
|
||||||
|
ret = pci_bus_set_aer_ops(dev->bus);
|
||||||
|
if (ret)
|
||||||
|
goto out_put;
|
||||||
|
ret = pci_bus_set_aer_ops(rpdev->bus);
|
||||||
|
if (ret)
|
||||||
|
goto out_put;
|
||||||
|
|
||||||
|
if (find_aer_device(rpdev, &edev))
|
||||||
|
aer_irq(-1, edev);
|
||||||
|
else
|
||||||
|
ret = -EINVAL;
|
||||||
|
out_put:
|
||||||
|
if (err_alloc)
|
||||||
|
kfree(err_alloc);
|
||||||
|
if (rperr_alloc)
|
||||||
|
kfree(rperr_alloc);
|
||||||
|
pci_dev_put(dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf,
|
||||||
|
size_t usize, loff_t *off)
|
||||||
|
{
|
||||||
|
struct aer_error_inj einj;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
if (usize != sizeof(struct aer_error_inj))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (copy_from_user(&einj, ubuf, usize))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
ret = aer_inject(&einj);
|
||||||
|
return ret ? ret : usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations aer_inject_fops = {
|
||||||
|
.write = aer_inject_write,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct miscdevice aer_inject_device = {
|
||||||
|
.minor = MISC_DYNAMIC_MINOR,
|
||||||
|
.name = "aer_inject",
|
||||||
|
.fops = &aer_inject_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init aer_inject_init(void)
|
||||||
|
{
|
||||||
|
return misc_register(&aer_inject_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit aer_inject_exit(void)
|
||||||
|
{
|
||||||
|
struct aer_error *err, *err_next;
|
||||||
|
unsigned long flags;
|
||||||
|
struct pci_bus_ops *bus_ops;
|
||||||
|
|
||||||
|
misc_deregister(&aer_inject_device);
|
||||||
|
|
||||||
|
while ((bus_ops = pci_bus_ops_pop())) {
|
||||||
|
pci_bus_set_ops(bus_ops->bus, bus_ops->ops);
|
||||||
|
kfree(bus_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&inject_lock, flags);
|
||||||
|
list_for_each_entry_safe(err, err_next,
|
||||||
|
&pci_bus_ops_list, list) {
|
||||||
|
list_del(&err->list);
|
||||||
|
kfree(err);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&inject_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(aer_inject_init);
|
||||||
|
module_exit(aer_inject_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("PCIE AER software error injector");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -77,7 +77,7 @@ void pci_no_aer(void)
|
||||||
*
|
*
|
||||||
* Invoked when Root Port detects AER messages.
|
* Invoked when Root Port detects AER messages.
|
||||||
**/
|
**/
|
||||||
static irqreturn_t aer_irq(int irq, void *context)
|
irqreturn_t aer_irq(int irq, void *context)
|
||||||
{
|
{
|
||||||
unsigned int status, id;
|
unsigned int status, id;
|
||||||
struct pcie_device *pdev = (struct pcie_device *)context;
|
struct pcie_device *pdev = (struct pcie_device *)context;
|
||||||
|
@ -126,6 +126,7 @@ static irqreturn_t aer_irq(int irq, void *context)
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(aer_irq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aer_alloc_rpc - allocate Root Port data structure
|
* aer_alloc_rpc - allocate Root Port data structure
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/pcieport_if.h>
|
#include <linux/pcieport_if.h>
|
||||||
#include <linux/aer.h>
|
#include <linux/aer.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#define AER_NONFATAL 0
|
#define AER_NONFATAL 0
|
||||||
#define AER_FATAL 1
|
#define AER_FATAL 1
|
||||||
|
@ -56,7 +57,11 @@ struct header_log_regs {
|
||||||
unsigned int dw3;
|
unsigned int dw3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */
|
||||||
struct aer_err_info {
|
struct aer_err_info {
|
||||||
|
struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
|
||||||
|
int error_dev_num;
|
||||||
|
u16 id;
|
||||||
int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */
|
int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */
|
||||||
int flags;
|
int flags;
|
||||||
unsigned int status; /* COR/UNCOR Error Status */
|
unsigned int status; /* COR/UNCOR Error Status */
|
||||||
|
@ -120,6 +125,7 @@ extern void aer_delete_rootport(struct aer_rpc *rpc);
|
||||||
extern int aer_init(struct pcie_device *dev);
|
extern int aer_init(struct pcie_device *dev);
|
||||||
extern void aer_isr(struct work_struct *work);
|
extern void aer_isr(struct work_struct *work);
|
||||||
extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
||||||
|
extern irqreturn_t aer_irq(int irq, void *context);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
extern int aer_osc_setup(struct pcie_device *pciedev);
|
extern int aer_osc_setup(struct pcie_device *pciedev);
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
#include "aerdrv.h"
|
#include "aerdrv.h"
|
||||||
|
|
||||||
static int forceload;
|
static int forceload;
|
||||||
|
static int nosourceid;
|
||||||
module_param(forceload, bool, 0);
|
module_param(forceload, bool, 0);
|
||||||
|
module_param(nosourceid, bool, 0);
|
||||||
|
|
||||||
int pci_enable_pcie_error_reporting(struct pci_dev *dev)
|
int pci_enable_pcie_error_reporting(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
|
@ -109,19 +111,23 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
|
||||||
#endif /* 0 */
|
#endif /* 0 */
|
||||||
|
|
||||||
|
|
||||||
static void set_device_error_reporting(struct pci_dev *dev, void *data)
|
static int set_device_error_reporting(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
bool enable = *((bool *)data);
|
bool enable = *((bool *)data);
|
||||||
|
|
||||||
if (dev->pcie_type != PCIE_RC_PORT &&
|
if (dev->pcie_type == PCIE_RC_PORT ||
|
||||||
dev->pcie_type != PCIE_SW_UPSTREAM_PORT &&
|
dev->pcie_type == PCIE_SW_UPSTREAM_PORT ||
|
||||||
dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT)
|
dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) {
|
||||||
return;
|
if (enable)
|
||||||
|
pci_enable_pcie_error_reporting(dev);
|
||||||
|
else
|
||||||
|
pci_disable_pcie_error_reporting(dev);
|
||||||
|
}
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
pci_enable_pcie_error_reporting(dev);
|
pcie_set_ecrc_checking(dev);
|
||||||
else
|
|
||||||
pci_disable_pcie_error_reporting(dev);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,73 +145,148 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
|
||||||
pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
|
pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_device_iter(struct device *device, void *data)
|
static inline int compare_device_id(struct pci_dev *dev,
|
||||||
|
struct aer_err_info *e_info)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) {
|
||||||
u16 id = *(unsigned long *)data;
|
|
||||||
u8 secondary, subordinate, d_bus = id >> 8;
|
|
||||||
|
|
||||||
if (device->bus == &pci_bus_type) {
|
|
||||||
dev = to_pci_dev(device);
|
|
||||||
if (id == ((dev->bus->number << 8) | dev->devfn)) {
|
|
||||||
/*
|
|
||||||
* Device ID match
|
|
||||||
*/
|
|
||||||
*(unsigned long*)data = (unsigned long)device;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If device is P2P, check if it is an upstream?
|
* Device ID match
|
||||||
*/
|
*/
|
||||||
if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
|
return 1;
|
||||||
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
|
|
||||||
&secondary);
|
|
||||||
pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
|
|
||||||
&subordinate);
|
|
||||||
if (d_bus >= secondary && d_bus <= subordinate) {
|
|
||||||
*(unsigned long*)data = (unsigned long)device;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
|
||||||
|
e_info->dev[e_info->error_dev_num] = dev;
|
||||||
|
e_info->error_dev_num++;
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define PCI_BUS(x) (((x) >> 8) & 0xff)
|
||||||
|
|
||||||
|
static int find_device_iter(struct pci_dev *dev, void *data)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
u32 status;
|
||||||
|
u32 mask;
|
||||||
|
u16 reg16;
|
||||||
|
int result;
|
||||||
|
struct aer_err_info *e_info = (struct aer_err_info *)data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When bus id is equal to 0, it might be a bad id
|
||||||
|
* reported by root port.
|
||||||
|
*/
|
||||||
|
if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
|
||||||
|
result = compare_device_id(dev, e_info);
|
||||||
|
if (result)
|
||||||
|
add_error_device(e_info, dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no multiple error, we stop
|
||||||
|
* or continue based on the id comparing.
|
||||||
|
*/
|
||||||
|
if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are multiple errors and id does match,
|
||||||
|
* We need continue to search other devices under
|
||||||
|
* the root port. Return 0 means that.
|
||||||
|
*/
|
||||||
|
if (result)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When either
|
||||||
|
* 1) nosourceid==y;
|
||||||
|
* 2) bus id is equal to 0. Some ports might lose the bus
|
||||||
|
* id of error source id;
|
||||||
|
* 3) There are multiple errors and prior id comparing fails;
|
||||||
|
* We check AER status registers to find the initial reporter.
|
||||||
|
*/
|
||||||
|
if (atomic_read(&dev->enable_cnt) == 0)
|
||||||
|
return 0;
|
||||||
|
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||||
|
if (!pos)
|
||||||
|
return 0;
|
||||||
|
/* Check if AER is enabled */
|
||||||
|
pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16);
|
||||||
|
if (!(reg16 & (
|
||||||
|
PCI_EXP_DEVCTL_CERE |
|
||||||
|
PCI_EXP_DEVCTL_NFERE |
|
||||||
|
PCI_EXP_DEVCTL_FERE |
|
||||||
|
PCI_EXP_DEVCTL_URRE)))
|
||||||
|
return 0;
|
||||||
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!pos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
mask = 0;
|
||||||
|
if (e_info->severity == AER_CORRECTABLE) {
|
||||||
|
pci_read_config_dword(dev,
|
||||||
|
pos + PCI_ERR_COR_STATUS,
|
||||||
|
&status);
|
||||||
|
pci_read_config_dword(dev,
|
||||||
|
pos + PCI_ERR_COR_MASK,
|
||||||
|
&mask);
|
||||||
|
if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) {
|
||||||
|
add_error_device(e_info, dev);
|
||||||
|
goto added;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pci_read_config_dword(dev,
|
||||||
|
pos + PCI_ERR_UNCOR_STATUS,
|
||||||
|
&status);
|
||||||
|
pci_read_config_dword(dev,
|
||||||
|
pos + PCI_ERR_UNCOR_MASK,
|
||||||
|
&mask);
|
||||||
|
if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) {
|
||||||
|
add_error_device(e_info, dev);
|
||||||
|
goto added;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
added:
|
||||||
|
if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find_source_device - search through device hierarchy for source device
|
* find_source_device - search through device hierarchy for source device
|
||||||
* @parent: pointer to Root Port pci_dev data structure
|
* @parent: pointer to Root Port pci_dev data structure
|
||||||
* @id: device ID of agent who sends an error message to this Root Port
|
* @err_info: including detailed error information such like id
|
||||||
*
|
*
|
||||||
* Invoked when error is detected at the Root Port.
|
* Invoked when error is detected at the Root Port.
|
||||||
*/
|
*/
|
||||||
static struct device* find_source_device(struct pci_dev *parent, u16 id)
|
static void find_source_device(struct pci_dev *parent,
|
||||||
|
struct aer_err_info *e_info)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev = parent;
|
struct pci_dev *dev = parent;
|
||||||
struct device *device;
|
int result;
|
||||||
unsigned long device_addr;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
/* Is Root Port an agent that sends error message? */
|
/* Is Root Port an agent that sends error message? */
|
||||||
if (id == ((dev->bus->number << 8) | dev->devfn))
|
result = find_device_iter(dev, e_info);
|
||||||
return &dev->dev;
|
if (result)
|
||||||
|
return;
|
||||||
|
|
||||||
do {
|
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
|
||||||
device_addr = id;
|
|
||||||
if ((status = device_for_each_child(&dev->dev,
|
|
||||||
&device_addr, find_device_iter))) {
|
|
||||||
device = (struct device*)device_addr;
|
|
||||||
dev = to_pci_dev(device);
|
|
||||||
if (id == ((dev->bus->number << 8) | dev->devfn))
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
}while (status);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_error_detected(struct pci_dev *dev, void *data)
|
static int report_error_detected(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
pci_ers_result_t vote;
|
pci_ers_result_t vote;
|
||||||
struct pci_error_handlers *err_handler;
|
struct pci_error_handlers *err_handler;
|
||||||
|
@ -230,16 +311,16 @@ static void report_error_detected(struct pci_dev *dev, void *data)
|
||||||
dev->driver ?
|
dev->driver ?
|
||||||
"no AER-aware driver" : "no driver");
|
"no AER-aware driver" : "no driver");
|
||||||
}
|
}
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_handler = dev->driver->err_handler;
|
err_handler = dev->driver->err_handler;
|
||||||
vote = err_handler->error_detected(dev, result_data->state);
|
vote = err_handler->error_detected(dev, result_data->state);
|
||||||
result_data->result = merge_result(result_data->result, vote);
|
result_data->result = merge_result(result_data->result, vote);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_mmio_enabled(struct pci_dev *dev, void *data)
|
static int report_mmio_enabled(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
pci_ers_result_t vote;
|
pci_ers_result_t vote;
|
||||||
struct pci_error_handlers *err_handler;
|
struct pci_error_handlers *err_handler;
|
||||||
|
@ -249,15 +330,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data)
|
||||||
if (!dev->driver ||
|
if (!dev->driver ||
|
||||||
!dev->driver->err_handler ||
|
!dev->driver->err_handler ||
|
||||||
!dev->driver->err_handler->mmio_enabled)
|
!dev->driver->err_handler->mmio_enabled)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
err_handler = dev->driver->err_handler;
|
err_handler = dev->driver->err_handler;
|
||||||
vote = err_handler->mmio_enabled(dev);
|
vote = err_handler->mmio_enabled(dev);
|
||||||
result_data->result = merge_result(result_data->result, vote);
|
result_data->result = merge_result(result_data->result, vote);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_slot_reset(struct pci_dev *dev, void *data)
|
static int report_slot_reset(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
pci_ers_result_t vote;
|
pci_ers_result_t vote;
|
||||||
struct pci_error_handlers *err_handler;
|
struct pci_error_handlers *err_handler;
|
||||||
|
@ -267,15 +348,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data)
|
||||||
if (!dev->driver ||
|
if (!dev->driver ||
|
||||||
!dev->driver->err_handler ||
|
!dev->driver->err_handler ||
|
||||||
!dev->driver->err_handler->slot_reset)
|
!dev->driver->err_handler->slot_reset)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
err_handler = dev->driver->err_handler;
|
err_handler = dev->driver->err_handler;
|
||||||
vote = err_handler->slot_reset(dev);
|
vote = err_handler->slot_reset(dev);
|
||||||
result_data->result = merge_result(result_data->result, vote);
|
result_data->result = merge_result(result_data->result, vote);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_resume(struct pci_dev *dev, void *data)
|
static int report_resume(struct pci_dev *dev, void *data)
|
||||||
{
|
{
|
||||||
struct pci_error_handlers *err_handler;
|
struct pci_error_handlers *err_handler;
|
||||||
|
|
||||||
|
@ -284,11 +365,11 @@ static void report_resume(struct pci_dev *dev, void *data)
|
||||||
if (!dev->driver ||
|
if (!dev->driver ||
|
||||||
!dev->driver->err_handler ||
|
!dev->driver->err_handler ||
|
||||||
!dev->driver->err_handler->resume)
|
!dev->driver->err_handler->resume)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
err_handler = dev->driver->err_handler;
|
err_handler = dev->driver->err_handler;
|
||||||
err_handler->resume(dev);
|
err_handler->resume(dev);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,7 +386,7 @@ static void report_resume(struct pci_dev *dev, void *data)
|
||||||
static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
|
static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
|
||||||
enum pci_channel_state state,
|
enum pci_channel_state state,
|
||||||
char *error_mesg,
|
char *error_mesg,
|
||||||
void (*cb)(struct pci_dev *, void *))
|
int (*cb)(struct pci_dev *, void *))
|
||||||
{
|
{
|
||||||
struct aer_broadcast_data result_data;
|
struct aer_broadcast_data result_data;
|
||||||
|
|
||||||
|
@ -497,12 +578,12 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
|
||||||
*/
|
*/
|
||||||
static void handle_error_source(struct pcie_device * aerdev,
|
static void handle_error_source(struct pcie_device * aerdev,
|
||||||
struct pci_dev *dev,
|
struct pci_dev *dev,
|
||||||
struct aer_err_info info)
|
struct aer_err_info *info)
|
||||||
{
|
{
|
||||||
pci_ers_result_t status = 0;
|
pci_ers_result_t status = 0;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
if (info.severity == AER_CORRECTABLE) {
|
if (info->severity == AER_CORRECTABLE) {
|
||||||
/*
|
/*
|
||||||
* Correctable error does not need software intevention.
|
* Correctable error does not need software intevention.
|
||||||
* No need to go through error recovery process.
|
* No need to go through error recovery process.
|
||||||
|
@ -510,9 +591,9 @@ static void handle_error_source(struct pcie_device * aerdev,
|
||||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
if (pos)
|
if (pos)
|
||||||
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
|
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
|
||||||
info.status);
|
info->status);
|
||||||
} else {
|
} else {
|
||||||
status = do_recovery(aerdev, dev, info.severity);
|
status = do_recovery(aerdev, dev, info->severity);
|
||||||
if (status == PCI_ERS_RESULT_RECOVERED) {
|
if (status == PCI_ERS_RESULT_RECOVERED) {
|
||||||
dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
|
dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
|
||||||
"successfully recovered\n");
|
"successfully recovered\n");
|
||||||
|
@ -661,6 +742,28 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||||
return AER_SUCCESS;
|
return AER_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void aer_process_err_devices(struct pcie_device *p_device,
|
||||||
|
struct aer_err_info *e_info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!e_info->dev[0]) {
|
||||||
|
dev_printk(KERN_DEBUG, &p_device->port->dev,
|
||||||
|
"can't find device of ID%04x\n",
|
||||||
|
e_info->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
|
||||||
|
if (get_device_error_info(e_info->dev[i], e_info) ==
|
||||||
|
AER_SUCCESS) {
|
||||||
|
aer_print_error(e_info->dev[i], e_info);
|
||||||
|
handle_error_source(p_device,
|
||||||
|
e_info->dev[i],
|
||||||
|
e_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aer_isr_one_error - consume an error detected by root port
|
* aer_isr_one_error - consume an error detected by root port
|
||||||
* @p_device: pointer to error root port service device
|
* @p_device: pointer to error root port service device
|
||||||
|
@ -669,10 +772,16 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||||
static void aer_isr_one_error(struct pcie_device *p_device,
|
static void aer_isr_one_error(struct pcie_device *p_device,
|
||||||
struct aer_err_source *e_src)
|
struct aer_err_source *e_src)
|
||||||
{
|
{
|
||||||
struct device *s_device;
|
struct aer_err_info *e_info;
|
||||||
struct aer_err_info e_info = {0, 0, 0,};
|
|
||||||
int i;
|
int i;
|
||||||
u16 id;
|
|
||||||
|
/* struct aer_err_info might be big, so we allocate it with slab */
|
||||||
|
e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL);
|
||||||
|
if (e_info == NULL) {
|
||||||
|
dev_printk(KERN_DEBUG, &p_device->port->dev,
|
||||||
|
"Can't allocate mem when processing AER errors\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There is a possibility that both correctable error and
|
* There is a possibility that both correctable error and
|
||||||
|
@ -684,31 +793,26 @@ static void aer_isr_one_error(struct pcie_device *p_device,
|
||||||
if (!(e_src->status & i))
|
if (!(e_src->status & i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
memset(e_info, 0, sizeof(struct aer_err_info));
|
||||||
|
|
||||||
/* Init comprehensive error information */
|
/* Init comprehensive error information */
|
||||||
if (i & PCI_ERR_ROOT_COR_RCV) {
|
if (i & PCI_ERR_ROOT_COR_RCV) {
|
||||||
id = ERR_COR_ID(e_src->id);
|
e_info->id = ERR_COR_ID(e_src->id);
|
||||||
e_info.severity = AER_CORRECTABLE;
|
e_info->severity = AER_CORRECTABLE;
|
||||||
} else {
|
} else {
|
||||||
id = ERR_UNCOR_ID(e_src->id);
|
e_info->id = ERR_UNCOR_ID(e_src->id);
|
||||||
e_info.severity = ((e_src->status >> 6) & 1);
|
e_info->severity = ((e_src->status >> 6) & 1);
|
||||||
}
|
}
|
||||||
if (e_src->status &
|
if (e_src->status &
|
||||||
(PCI_ERR_ROOT_MULTI_COR_RCV |
|
(PCI_ERR_ROOT_MULTI_COR_RCV |
|
||||||
PCI_ERR_ROOT_MULTI_UNCOR_RCV))
|
PCI_ERR_ROOT_MULTI_UNCOR_RCV))
|
||||||
e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
|
e_info->flags |= AER_MULTI_ERROR_VALID_FLAG;
|
||||||
if (!(s_device = find_source_device(p_device->port, id))) {
|
|
||||||
printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
|
find_source_device(p_device->port, e_info);
|
||||||
__func__, id);
|
aer_process_err_devices(p_device, e_info);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
|
|
||||||
AER_SUCCESS) {
|
|
||||||
aer_print_error(to_pci_dev(s_device), &e_info);
|
|
||||||
handle_error_source(p_device,
|
|
||||||
to_pci_dev(s_device),
|
|
||||||
e_info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfree(e_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
131
drivers/pci/pcie/aer/ecrc.c
Normal file
131
drivers/pci/pcie/aer/ecrc.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Enables/disables PCIe ECRC checking.
|
||||||
|
*
|
||||||
|
* (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
* Andrew Patterson <andrew.patterson@hp.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci_regs.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include "../../pci.h"
|
||||||
|
|
||||||
|
#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */
|
||||||
|
#define ECRC_POLICY_OFF 1 /* ECRC off for performance */
|
||||||
|
#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */
|
||||||
|
|
||||||
|
static int ecrc_policy = ECRC_POLICY_DEFAULT;
|
||||||
|
|
||||||
|
static const char *ecrc_policy_str[] = {
|
||||||
|
[ECRC_POLICY_DEFAULT] = "bios",
|
||||||
|
[ECRC_POLICY_OFF] = "off",
|
||||||
|
[ECRC_POLICY_ON] = "on"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable_ercr_checking - enable PCIe ECRC checking for a device
|
||||||
|
* @dev: the PCI device
|
||||||
|
*
|
||||||
|
* Returns 0 on success, or negative on failure.
|
||||||
|
*/
|
||||||
|
static int enable_ecrc_checking(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
u32 reg32;
|
||||||
|
|
||||||
|
if (!dev->is_pcie)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!pos)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32);
|
||||||
|
if (reg32 & PCI_ERR_CAP_ECRC_GENC)
|
||||||
|
reg32 |= PCI_ERR_CAP_ECRC_GENE;
|
||||||
|
if (reg32 & PCI_ERR_CAP_ECRC_CHKC)
|
||||||
|
reg32 |= PCI_ERR_CAP_ECRC_CHKE;
|
||||||
|
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disable_ercr_checking - disables PCIe ECRC checking for a device
|
||||||
|
* @dev: the PCI device
|
||||||
|
*
|
||||||
|
* Returns 0 on success, or negative on failure.
|
||||||
|
*/
|
||||||
|
static int disable_ecrc_checking(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
u32 reg32;
|
||||||
|
|
||||||
|
if (!dev->is_pcie)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!pos)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32);
|
||||||
|
reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
|
||||||
|
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy
|
||||||
|
* @dev: the PCI device
|
||||||
|
*/
|
||||||
|
void pcie_set_ecrc_checking(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
switch (ecrc_policy) {
|
||||||
|
case ECRC_POLICY_DEFAULT:
|
||||||
|
return;
|
||||||
|
case ECRC_POLICY_OFF:
|
||||||
|
disable_ecrc_checking(dev);
|
||||||
|
break;
|
||||||
|
case ECRC_POLICY_ON:
|
||||||
|
enable_ecrc_checking(dev);;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcie_ecrc_get_policy - parse kernel command-line ecrc option
|
||||||
|
*/
|
||||||
|
void pcie_ecrc_get_policy(char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++)
|
||||||
|
if (!strncmp(str, ecrc_policy_str[i],
|
||||||
|
strlen(ecrc_policy_str[i])))
|
||||||
|
break;
|
||||||
|
if (i >= ARRAY_SIZE(ecrc_policy_str))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ecrc_policy = i;
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -193,7 +193,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
||||||
res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
|
res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
|
||||||
if (type == pci_bar_io) {
|
if (type == pci_bar_io) {
|
||||||
l &= PCI_BASE_ADDRESS_IO_MASK;
|
l &= PCI_BASE_ADDRESS_IO_MASK;
|
||||||
mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
|
mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT;
|
||||||
} else {
|
} else {
|
||||||
l &= PCI_BASE_ADDRESS_MEM_MASK;
|
l &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||||
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
|
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
|
||||||
|
@ -237,6 +237,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
||||||
dev_printk(KERN_DEBUG, &dev->dev,
|
dev_printk(KERN_DEBUG, &dev->dev,
|
||||||
"reg %x 64bit mmio: %pR\n", pos, res);
|
"reg %x 64bit mmio: %pR\n", pos, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res->flags |= IORESOURCE_MEM_64;
|
||||||
} else {
|
} else {
|
||||||
sz = pci_size(l, sz, mask);
|
sz = pci_size(l, sz, mask);
|
||||||
|
|
||||||
|
@ -287,7 +289,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!child->parent) /* It's a host bus, nothing to read */
|
if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dev->transparent) {
|
if (dev->transparent) {
|
||||||
|
@ -362,7 +364,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (base <= limit) {
|
if (base <= limit) {
|
||||||
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
|
res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
|
||||||
|
IORESOURCE_MEM | IORESOURCE_PREFETCH;
|
||||||
|
if (res->flags & PCI_PREF_RANGE_TYPE_64)
|
||||||
|
res->flags |= IORESOURCE_MEM_64;
|
||||||
res->start = base;
|
res->start = base;
|
||||||
res->end = limit + 0xfffff;
|
res->end = limit + 0xfffff;
|
||||||
dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n",
|
dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n",
|
||||||
|
|
|
@ -1133,6 +1133,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
|
||||||
switch (dev->subsystem_device) {
|
switch (dev->subsystem_device) {
|
||||||
case 0x1751: /* M2N notebook */
|
case 0x1751: /* M2N notebook */
|
||||||
case 0x1821: /* M5N notebook */
|
case 0x1821: /* M5N notebook */
|
||||||
|
case 0x1897: /* A6L notebook */
|
||||||
asus_hides_smbus = 1;
|
asus_hides_smbus = 1;
|
||||||
}
|
}
|
||||||
else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
|
else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
|
||||||
|
@ -1163,6 +1164,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
|
||||||
switch (dev->subsystem_device) {
|
switch (dev->subsystem_device) {
|
||||||
case 0x12bc: /* HP D330L */
|
case 0x12bc: /* HP D330L */
|
||||||
case 0x12bd: /* HP D530 */
|
case 0x12bd: /* HP D530 */
|
||||||
|
case 0x006a: /* HP Compaq nx9500 */
|
||||||
asus_hides_smbus = 1;
|
asus_hides_smbus = 1;
|
||||||
}
|
}
|
||||||
else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
|
else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
|
||||||
|
@ -2016,6 +2018,28 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
|
||||||
PCI_DEVICE_ID_NX2_5709S,
|
PCI_DEVICE_ID_NX2_5709S,
|
||||||
quirk_brcm_570x_limit_vpd);
|
quirk_brcm_570x_limit_vpd);
|
||||||
|
|
||||||
|
/* Originally in EDAC sources for i82875P:
|
||||||
|
* Intel tells BIOS developers to hide device 6 which
|
||||||
|
* configures the overflow device access containing
|
||||||
|
* the DRBs - this is where we expose device 6.
|
||||||
|
* http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
|
||||||
|
*/
|
||||||
|
static void __devinit quirk_unhide_mch_dev6(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
if (pci_read_config_byte(dev, 0xF4, ®) == 0 && !(reg & 0x02)) {
|
||||||
|
dev_info(&dev->dev, "Enabling MCH 'Overflow' Device\n");
|
||||||
|
pci_write_config_byte(dev, 0xF4, reg | 0x02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB,
|
||||||
|
quirk_unhide_mch_dev6);
|
||||||
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB,
|
||||||
|
quirk_unhide_mch_dev6);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MSI
|
#ifdef CONFIG_PCI_MSI
|
||||||
/* Some chipsets do not support MSI. We cannot easily rely on setting
|
/* Some chipsets do not support MSI. We cannot easily rely on setting
|
||||||
* PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
|
* PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
|
||||||
|
|
|
@ -32,8 +32,6 @@ static void pci_stop_dev(struct pci_dev *dev)
|
||||||
|
|
||||||
static void pci_destroy_dev(struct pci_dev *dev)
|
static void pci_destroy_dev(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
pci_stop_dev(dev);
|
|
||||||
|
|
||||||
/* Remove the device from the device lists, and prevent any further
|
/* Remove the device from the device lists, and prevent any further
|
||||||
* list accesses from this device */
|
* list accesses from this device */
|
||||||
down_write(&pci_bus_sem);
|
down_write(&pci_bus_sem);
|
||||||
|
|
|
@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
|
||||||
if (pdev->is_pcie)
|
if (pdev->is_pcie)
|
||||||
return NULL;
|
return NULL;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!pdev->bus->parent)
|
if (pci_is_root_bus(pdev->bus))
|
||||||
break;
|
break;
|
||||||
pdev = pdev->bus->self;
|
pdev = pdev->bus->self;
|
||||||
/* a p2p bridge */
|
/* a p2p bridge */
|
||||||
|
@ -114,36 +114,6 @@ pci_find_next_bus(const struct pci_bus *from)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_LEGACY
|
#ifdef CONFIG_PCI_LEGACY
|
||||||
/**
|
|
||||||
* pci_find_slot - locate PCI device from a given PCI slot
|
|
||||||
* @bus: number of PCI bus on which desired PCI device resides
|
|
||||||
* @devfn: encodes number of PCI slot in which the desired PCI
|
|
||||||
* device resides and the logical device number within that slot
|
|
||||||
* in case of multi-function devices.
|
|
||||||
*
|
|
||||||
* Given a PCI bus and slot/function number, the desired PCI device
|
|
||||||
* is located in system global list of PCI devices. If the device
|
|
||||||
* is found, a pointer to its data structure is returned. If no
|
|
||||||
* device is found, %NULL is returned.
|
|
||||||
*
|
|
||||||
* NOTE: Do not use this function any more; use pci_get_slot() instead, as
|
|
||||||
* the PCI device returned by this function can disappear at any moment in
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
|
|
||||||
{
|
|
||||||
struct pci_dev *dev = NULL;
|
|
||||||
|
|
||||||
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
|
|
||||||
if (dev->bus->number == bus && dev->devfn == devfn) {
|
|
||||||
pci_dev_put(dev);
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(pci_find_slot);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_find_device - begin or continue searching for a PCI device by vendor/device id
|
* pci_find_device - begin or continue searching for a PCI device by vendor/device id
|
||||||
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
|
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
|
||||||
|
|
|
@ -58,7 +58,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
|
||||||
res = list->res;
|
res = list->res;
|
||||||
idx = res - &list->dev->resource[0];
|
idx = res - &list->dev->resource[0];
|
||||||
if (pci_assign_resource(list->dev, idx)) {
|
if (pci_assign_resource(list->dev, idx)) {
|
||||||
/* FIXME: get rid of this */
|
|
||||||
res->start = 0;
|
res->start = 0;
|
||||||
res->end = 0;
|
res->end = 0;
|
||||||
res->flags = 0;
|
res->flags = 0;
|
||||||
|
@ -143,6 +142,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
|
||||||
struct pci_dev *bridge = bus->self;
|
struct pci_dev *bridge = bus->self;
|
||||||
struct pci_bus_region region;
|
struct pci_bus_region region;
|
||||||
u32 l, bu, lu, io_upper16;
|
u32 l, bu, lu, io_upper16;
|
||||||
|
int pref_mem64;
|
||||||
|
|
||||||
if (pci_is_enabled(bridge))
|
if (pci_is_enabled(bridge))
|
||||||
return;
|
return;
|
||||||
|
@ -198,16 +198,22 @@ static void pci_setup_bridge(struct pci_bus *bus)
|
||||||
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
|
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
|
||||||
|
|
||||||
/* Set up PREF base/limit. */
|
/* Set up PREF base/limit. */
|
||||||
|
pref_mem64 = 0;
|
||||||
bu = lu = 0;
|
bu = lu = 0;
|
||||||
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
|
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
|
||||||
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
|
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
|
||||||
|
int width = 8;
|
||||||
l = (region.start >> 16) & 0xfff0;
|
l = (region.start >> 16) & 0xfff0;
|
||||||
l |= region.end & 0xfff00000;
|
l |= region.end & 0xfff00000;
|
||||||
bu = upper_32_bits(region.start);
|
if (bus->resource[2]->flags & IORESOURCE_MEM_64) {
|
||||||
lu = upper_32_bits(region.end);
|
pref_mem64 = 1;
|
||||||
dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n",
|
bu = upper_32_bits(region.start);
|
||||||
(unsigned long long)region.start,
|
lu = upper_32_bits(region.end);
|
||||||
(unsigned long long)region.end);
|
width = 16;
|
||||||
|
}
|
||||||
|
dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n",
|
||||||
|
width, (unsigned long long)region.start,
|
||||||
|
width, (unsigned long long)region.end);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
l = 0x0000fff0;
|
l = 0x0000fff0;
|
||||||
|
@ -215,9 +221,11 @@ static void pci_setup_bridge(struct pci_bus *bus)
|
||||||
}
|
}
|
||||||
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
|
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
|
||||||
|
|
||||||
/* Set the upper 32 bits of PREF base & limit. */
|
if (pref_mem64) {
|
||||||
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
|
/* Set the upper 32 bits of PREF base & limit. */
|
||||||
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
|
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
|
||||||
|
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
|
||||||
|
}
|
||||||
|
|
||||||
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
|
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
|
||||||
}
|
}
|
||||||
|
@ -255,8 +263,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
|
||||||
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
||||||
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
|
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
|
||||||
}
|
}
|
||||||
if (pmem)
|
if (pmem) {
|
||||||
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
|
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
|
||||||
|
if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
|
||||||
|
b_res[2].flags |= IORESOURCE_MEM_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* double check if bridge does support 64 bit pref */
|
||||||
|
if (b_res[2].flags & IORESOURCE_MEM_64) {
|
||||||
|
u32 mem_base_hi, tmp;
|
||||||
|
pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32,
|
||||||
|
&mem_base_hi);
|
||||||
|
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
|
||||||
|
0xffffffff);
|
||||||
|
pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
|
||||||
|
if (!tmp)
|
||||||
|
b_res[2].flags &= ~IORESOURCE_MEM_64;
|
||||||
|
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
|
||||||
|
mem_base_hi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for sizing routines: find first available
|
/* Helper function for sizing routines: find first available
|
||||||
|
@ -336,6 +361,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
|
||||||
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
|
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
|
||||||
int order, max_order;
|
int order, max_order;
|
||||||
struct resource *b_res = find_free_bus_resource(bus, type);
|
struct resource *b_res = find_free_bus_resource(bus, type);
|
||||||
|
unsigned int mem64_mask = 0;
|
||||||
|
|
||||||
if (!b_res)
|
if (!b_res)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -344,6 +370,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
|
||||||
max_order = 0;
|
max_order = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
|
mem64_mask = b_res->flags & IORESOURCE_MEM_64;
|
||||||
|
b_res->flags &= ~IORESOURCE_MEM_64;
|
||||||
|
|
||||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -372,6 +401,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
|
||||||
aligns[order] += align;
|
aligns[order] += align;
|
||||||
if (order > max_order)
|
if (order > max_order)
|
||||||
max_order = order;
|
max_order = order;
|
||||||
|
mem64_mask &= r->flags & IORESOURCE_MEM_64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,6 +426,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
|
||||||
b_res->start = min_align;
|
b_res->start = min_align;
|
||||||
b_res->end = size + min_align - 1;
|
b_res->end = size + min_align - 1;
|
||||||
b_res->flags |= IORESOURCE_STARTALIGN;
|
b_res->flags |= IORESOURCE_STARTALIGN;
|
||||||
|
b_res->flags |= mem64_mask;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,23 +135,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PCI_QUIRKS */
|
#endif /* CONFIG_PCI_QUIRKS */
|
||||||
|
|
||||||
int pci_assign_resource(struct pci_dev *dev, int resno)
|
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
|
||||||
|
int resno)
|
||||||
{
|
{
|
||||||
struct pci_bus *bus = dev->bus;
|
|
||||||
struct resource *res = dev->resource + resno;
|
struct resource *res = dev->resource + resno;
|
||||||
resource_size_t size, min, align;
|
resource_size_t size, min, align;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = resource_size(res);
|
size = resource_size(res);
|
||||||
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
|
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
|
||||||
|
|
||||||
align = resource_alignment(res);
|
align = resource_alignment(res);
|
||||||
if (!align) {
|
|
||||||
dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
|
|
||||||
"alignment) %pR flags %#lx\n",
|
|
||||||
resno, res, res->flags);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First, try exact prefetching match.. */
|
/* First, try exact prefetching match.. */
|
||||||
ret = pci_bus_alloc_resource(bus, res, size, align, min,
|
ret = pci_bus_alloc_resource(bus, res, size, align, min,
|
||||||
|
@ -169,10 +162,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
|
||||||
pcibios_align_resource, dev);
|
pcibios_align_resource, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (!ret) {
|
||||||
dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
|
|
||||||
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
|
|
||||||
} else {
|
|
||||||
res->flags &= ~IORESOURCE_STARTALIGN;
|
res->flags &= ~IORESOURCE_STARTALIGN;
|
||||||
if (resno < PCI_BRIDGE_RESOURCES)
|
if (resno < PCI_BRIDGE_RESOURCES)
|
||||||
pci_update_resource(dev, resno);
|
pci_update_resource(dev, resno);
|
||||||
|
@ -181,6 +171,39 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pci_assign_resource(struct pci_dev *dev, int resno)
|
||||||
|
{
|
||||||
|
struct resource *res = dev->resource + resno;
|
||||||
|
resource_size_t align;
|
||||||
|
struct pci_bus *bus;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
align = resource_alignment(res);
|
||||||
|
if (!align) {
|
||||||
|
dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
|
||||||
|
"alignment) %pR flags %#lx\n",
|
||||||
|
resno, res, res->flags);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = dev->bus;
|
||||||
|
while ((ret = __pci_assign_resource(bus, dev, resno))) {
|
||||||
|
if (bus->parent && bus->self->transparent)
|
||||||
|
bus = bus->parent;
|
||||||
|
else
|
||||||
|
bus = NULL;
|
||||||
|
if (bus)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
|
||||||
|
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
|
int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
|
||||||
{
|
{
|
||||||
|
|
|
@ -307,6 +307,45 @@ void pci_destroy_slot(struct pci_slot *slot)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_destroy_slot);
|
EXPORT_SYMBOL_GPL(pci_destroy_slot);
|
||||||
|
|
||||||
|
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
|
||||||
|
#include <linux/pci_hotplug.h>
|
||||||
|
/**
|
||||||
|
* pci_hp_create_link - create symbolic link to the hotplug driver module.
|
||||||
|
* @slot: struct pci_slot
|
||||||
|
*
|
||||||
|
* Helper function for pci_hotplug_core.c to create symbolic link to
|
||||||
|
* the hotplug driver module.
|
||||||
|
*/
|
||||||
|
void pci_hp_create_module_link(struct pci_slot *pci_slot)
|
||||||
|
{
|
||||||
|
struct hotplug_slot *slot = pci_slot->hotplug;
|
||||||
|
struct kobject *kobj = NULL;
|
||||||
|
int no_warn;
|
||||||
|
|
||||||
|
if (!slot || !slot->ops)
|
||||||
|
return;
|
||||||
|
kobj = kset_find_obj(module_kset, slot->ops->mod_name);
|
||||||
|
if (!kobj)
|
||||||
|
return;
|
||||||
|
no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module");
|
||||||
|
kobject_put(kobj);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_hp_remove_link - remove symbolic link to the hotplug driver module.
|
||||||
|
* @slot: struct pci_slot
|
||||||
|
*
|
||||||
|
* Helper function for pci_hotplug_core.c to remove symbolic link to
|
||||||
|
* the hotplug driver module.
|
||||||
|
*/
|
||||||
|
void pci_hp_remove_module_link(struct pci_slot *pci_slot)
|
||||||
|
{
|
||||||
|
sysfs_remove_link(&pci_slot->kobj, "module");
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_hp_remove_module_link);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int pci_slot_init(void)
|
static int pci_slot_init(void)
|
||||||
{
|
{
|
||||||
struct kset *pci_bus_kset;
|
struct kset *pci_bus_kset;
|
||||||
|
|
|
@ -49,6 +49,8 @@ struct resource_list {
|
||||||
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
|
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
|
||||||
#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
|
#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
|
||||||
|
|
||||||
|
#define IORESOURCE_MEM_64 0x00100000
|
||||||
|
|
||||||
#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
|
#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
|
||||||
#define IORESOURCE_DISABLED 0x10000000
|
#define IORESOURCE_DISABLED 0x10000000
|
||||||
#define IORESOURCE_UNSET 0x20000000
|
#define IORESOURCE_UNSET 0x20000000
|
||||||
|
|
|
@ -15,7 +15,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct pci_bus *pbus = pdev->bus;
|
struct pci_bus *pbus = pdev->bus;
|
||||||
/* Find a PCI root bus */
|
/* Find a PCI root bus */
|
||||||
while (pbus->parent)
|
while (!pci_is_root_bus(pbus))
|
||||||
pbus = pbus->parent;
|
pbus = pbus->parent;
|
||||||
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
|
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
|
||||||
pbus->number);
|
pbus->number);
|
||||||
|
@ -23,7 +23,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
|
||||||
|
|
||||||
static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
|
static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
|
||||||
{
|
{
|
||||||
if (pbus->parent)
|
if (!pci_is_root_bus(pbus))
|
||||||
return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
|
return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
|
||||||
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
|
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
|
||||||
pbus->number);
|
pbus->number);
|
||||||
|
|
|
@ -607,8 +607,6 @@ extern void pci_sort_breadthfirst(void);
|
||||||
struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
|
struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
|
||||||
unsigned int device,
|
unsigned int device,
|
||||||
struct pci_dev *from);
|
struct pci_dev *from);
|
||||||
struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
|
|
||||||
unsigned int devfn);
|
|
||||||
#endif /* CONFIG_PCI_LEGACY */
|
#endif /* CONFIG_PCI_LEGACY */
|
||||||
|
|
||||||
enum pci_lost_interrupt_reason {
|
enum pci_lost_interrupt_reason {
|
||||||
|
@ -647,6 +645,7 @@ int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
|
||||||
int where, u16 val);
|
int where, u16 val);
|
||||||
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
|
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
|
||||||
int where, u32 val);
|
int where, u32 val);
|
||||||
|
struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops);
|
||||||
|
|
||||||
static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
|
static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
|
||||||
{
|
{
|
||||||
|
@ -711,8 +710,8 @@ int pcix_get_mmrbc(struct pci_dev *dev);
|
||||||
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
|
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
|
||||||
int pcie_get_readrq(struct pci_dev *dev);
|
int pcie_get_readrq(struct pci_dev *dev);
|
||||||
int pcie_set_readrq(struct pci_dev *dev, int rq);
|
int pcie_set_readrq(struct pci_dev *dev, int rq);
|
||||||
|
int __pci_reset_function(struct pci_dev *dev);
|
||||||
int pci_reset_function(struct pci_dev *dev);
|
int pci_reset_function(struct pci_dev *dev);
|
||||||
int pci_execute_reset_function(struct pci_dev *dev);
|
|
||||||
void pci_update_resource(struct pci_dev *dev, int resno);
|
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_assign_resource(struct pci_dev *dev, int i);
|
||||||
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
|
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
|
||||||
|
@ -732,7 +731,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
|
||||||
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
|
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
|
||||||
bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
|
bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
|
||||||
void pci_pme_active(struct pci_dev *dev, bool enable);
|
void pci_pme_active(struct pci_dev *dev, bool enable);
|
||||||
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
|
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable);
|
||||||
int pci_wake_from_d3(struct pci_dev *dev, bool enable);
|
int pci_wake_from_d3(struct pci_dev *dev, bool enable);
|
||||||
pci_power_t pci_target_state(struct pci_dev *dev);
|
pci_power_t pci_target_state(struct pci_dev *dev);
|
||||||
int pci_prepare_to_sleep(struct pci_dev *dev);
|
int pci_prepare_to_sleep(struct pci_dev *dev);
|
||||||
|
@ -798,7 +797,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
|
||||||
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
||||||
int pass);
|
int pass);
|
||||||
|
|
||||||
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
|
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||||
void *userdata);
|
void *userdata);
|
||||||
int pci_cfg_space_size_ext(struct pci_dev *dev);
|
int pci_cfg_space_size_ext(struct pci_dev *dev);
|
||||||
int pci_cfg_space_size(struct pci_dev *dev);
|
int pci_cfg_space_size(struct pci_dev *dev);
|
||||||
|
@ -888,6 +887,17 @@ static inline int pcie_aspm_enabled(void)
|
||||||
extern int pcie_aspm_enabled(void);
|
extern int pcie_aspm_enabled(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_PCIE_ECRC
|
||||||
|
static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static inline void pcie_ecrc_get_policy(char *str) {};
|
||||||
|
#else
|
||||||
|
extern void pcie_set_ecrc_checking(struct pci_dev *dev);
|
||||||
|
extern void pcie_ecrc_get_policy(char *str);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1)
|
#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1)
|
||||||
|
|
||||||
#ifdef CONFIG_HT_IRQ
|
#ifdef CONFIG_HT_IRQ
|
||||||
|
@ -944,12 +954,6 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct pci_dev *pci_find_slot(unsigned int bus,
|
|
||||||
unsigned int devfn)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct pci_dev *pci_get_device(unsigned int vendor,
|
static inline struct pci_dev *pci_get_device(unsigned int vendor,
|
||||||
unsigned int device,
|
unsigned int device,
|
||||||
struct pci_dev *from)
|
struct pci_dev *from)
|
||||||
|
@ -1105,6 +1109,10 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
|
||||||
|
|
||||||
#include <asm/pci.h>
|
#include <asm/pci.h>
|
||||||
|
|
||||||
|
#ifndef PCIBIOS_MAX_MEM_32
|
||||||
|
#define PCIBIOS_MAX_MEM_32 (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* these helpers provide future and backwards compatibility
|
/* these helpers provide future and backwards compatibility
|
||||||
* for accessing popular PCI BAR info */
|
* for accessing popular PCI BAR info */
|
||||||
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
|
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
|
||||||
|
@ -1261,5 +1269,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
|
||||||
|
extern void pci_hp_create_module_link(struct pci_slot *pci_slot);
|
||||||
|
extern void pci_hp_remove_module_link(struct pci_slot *pci_slot);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
#endif /* LINUX_PCI_H */
|
#endif /* LINUX_PCI_H */
|
||||||
|
|
|
@ -66,17 +66,10 @@ enum pcie_link_speed {
|
||||||
PCIE_LNK_SPEED_UNKNOWN = 0xFF,
|
PCIE_LNK_SPEED_UNKNOWN = 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hotplug_slot;
|
|
||||||
struct hotplug_slot_attribute {
|
|
||||||
struct attribute attr;
|
|
||||||
ssize_t (*show)(struct hotplug_slot *, char *);
|
|
||||||
ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
|
|
||||||
};
|
|
||||||
#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
|
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
|
||||||
* @owner: The module owner of this structure
|
* @owner: The module owner of this structure
|
||||||
|
* @mod_name: The module name (KBUILD_MODNAME) of this structure
|
||||||
* @enable_slot: Called when the user wants to enable a specific pci slot
|
* @enable_slot: Called when the user wants to enable a specific pci slot
|
||||||
* @disable_slot: Called when the user wants to disable a specific pci slot
|
* @disable_slot: Called when the user wants to disable a specific pci slot
|
||||||
* @set_attention_status: Called to set the specific slot's attention LED to
|
* @set_attention_status: Called to set the specific slot's attention LED to
|
||||||
|
@ -109,6 +102,7 @@ struct hotplug_slot_attribute {
|
||||||
*/
|
*/
|
||||||
struct hotplug_slot_ops {
|
struct hotplug_slot_ops {
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
const char *mod_name;
|
||||||
int (*enable_slot) (struct hotplug_slot *slot);
|
int (*enable_slot) (struct hotplug_slot *slot);
|
||||||
int (*disable_slot) (struct hotplug_slot *slot);
|
int (*disable_slot) (struct hotplug_slot *slot);
|
||||||
int (*set_attention_status) (struct hotplug_slot *slot, u8 value);
|
int (*set_attention_status) (struct hotplug_slot *slot, u8 value);
|
||||||
|
@ -167,12 +161,21 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
|
||||||
return pci_slot_name(slot->pci_slot);
|
return pci_slot_name(slot->pci_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr,
|
extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus,
|
||||||
const char *name);
|
int nr, const char *name,
|
||||||
|
struct module *owner, const char *mod_name);
|
||||||
extern int pci_hp_deregister(struct hotplug_slot *slot);
|
extern int pci_hp_deregister(struct hotplug_slot *slot);
|
||||||
extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
|
extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
|
||||||
struct hotplug_slot_info *info);
|
struct hotplug_slot_info *info);
|
||||||
|
|
||||||
|
static inline int pci_hp_register(struct hotplug_slot *slot,
|
||||||
|
struct pci_bus *pbus,
|
||||||
|
int devnr, const char *name)
|
||||||
|
{
|
||||||
|
return __pci_hp_register(slot, pbus, devnr, name,
|
||||||
|
THIS_MODULE, KBUILD_MODNAME);
|
||||||
|
}
|
||||||
|
|
||||||
/* PCI Setting Record (Type 0) */
|
/* PCI Setting Record (Type 0) */
|
||||||
struct hpp_type0 {
|
struct hpp_type0 {
|
||||||
u32 revision;
|
u32 revision;
|
||||||
|
|
|
@ -295,8 +295,9 @@
|
||||||
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
|
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
|
||||||
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
|
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
|
||||||
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
|
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
|
||||||
|
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
|
||||||
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
||||||
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
|
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
|
||||||
|
|
||||||
/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
|
/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
|
||||||
#define PCI_MSIX_FLAGS 2
|
#define PCI_MSIX_FLAGS 2
|
||||||
|
@ -304,7 +305,6 @@
|
||||||
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
||||||
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
|
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
|
||||||
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
|
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
|
||||||
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
|
|
||||||
|
|
||||||
/* CompactPCI Hotswap Register */
|
/* CompactPCI Hotswap Register */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue