Commit 59ef7a83 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 5165aece 2af5066f
...@@ -122,3 +122,10 @@ Description: ...@@ -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 ...@@ -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? ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 @@ ...@@ -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); ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 *), ...@@ -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 @@ ...@@ -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 ...@@ -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); ...@@ -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); ...@@ -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,
......
...@@ -190,7 +190,9 @@ struct hrt { ...@@ -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,7 +219,9 @@ struct slot_rt { ...@@ -217,7 +219,9 @@ 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),
...@@ -401,46 +405,57 @@ struct resource_lists { ...@@ -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; ...@@ -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) ...@@ -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,13 +590,12 @@ static inline u8 read_slot_enable(struct controller *ctrl) ...@@ -575,13 +590,12 @@ 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)
{ {
...@@ -607,14 +621,13 @@ static inline u8 get_controller_speed(struct controller *ctrl) ...@@ -607,14 +621,13 @@ static inline u8 get_controller_speed(struct controller *ctrl)
} }
/* /**
* 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) ...@@ -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 ...@@ -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 ...@@ -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) ...@@ -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
This diff is collapsed.
This diff is collapsed.
...@@ -94,12 +94,13 @@ static u8 evbuffer[1024]; ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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));
......
This diff is collapsed.
...@@ -1318,7 +1318,6 @@ error: ...@@ -1318,7 +1318,6 @@ error:
} }
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) ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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"); ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 = { ...@@ -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) ...@@ -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 @@ error: ...@@ -261,13 +156,8 @@ error:
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) ...@@ -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 = { ...@@ -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); ...@@ -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) ...@@ -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); ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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 @@ found: ...@@ -487,6 +487,8 @@ found:
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) ...@@ -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); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE; control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable) if (enable)
control |= PCI_MSI_FLAGS_ENABLE; control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
}
}
static void msi_set_enable(struct pci_dev *dev, int enable)
{
__msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable);
} }
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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 */
This diff is collapsed.
...@@ -10,3 +10,18 @@ config PCIEAER ...@@ -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"
#
# 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 @@ ...@@ -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
This diff is collapsed.
...@@ -77,7 +77,7 @@ void pci_no_aer(void) ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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); ...@@ -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);
......
This diff is collapsed.
/*
* 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, &reg32);
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, &reg32);
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;
}
This diff is collapsed.
...@@ -193,7 +193,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, &reg) == 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) ...@@ -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) ...@@ -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) ...@@ -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
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -49,6 +49,8 @@ struct resource_list { ...@@ -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) ...@@ -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) ...@@ -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);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment