Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (74 commits)
  PCI: make msi_free_irqs() to use msix_mask_irq() instead of open coded write
  PCI: Fix the NIU MSI-X problem in a better way
  PCI ASPM: remove get_root_port_link
  PCI ASPM: cleanup pcie_aspm_sanity_check
  PCI ASPM: remove has_switch field
  PCI ASPM: cleanup calc_Lx_latency
  PCI ASPM: cleanup pcie_aspm_get_cap_device
  PCI ASPM: cleanup clkpm checks
  PCI ASPM: cleanup __pcie_aspm_check_state_one
  PCI ASPM: cleanup initialization
  PCI ASPM: cleanup change input argument of aspm functions
  PCI ASPM: cleanup misc in struct pcie_link_state
  PCI ASPM: cleanup clkpm state in struct pcie_link_state
  PCI ASPM: cleanup latency field in struct pcie_link_state
  PCI ASPM: cleanup aspm state field in struct pcie_link_state
  PCI ASPM: fix typo in struct pcie_link_state
  PCI: drivers/pci/slot.c should depend on CONFIG_SYSFS
  PCI: remove redundant __msi_set_enable()
  PCI PM: consistently use type bool for wake enable variable
  x86/ACPI: Correct maximum allowed _CRS returned resources and warn if exceeded
  ...
This commit is contained in:
Linus Torvalds 2009-06-22 11:59:51 -07:00
commit 59ef7a83f1
55 changed files with 3031 additions and 2194 deletions

View File

@ -122,3 +122,10 @@ Description:
This symbolic link appears when a device is a Virtual Function.
The symbolic link points to the PCI device sysfs entry of the
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.

View File

@ -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
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
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.
@ -246,3 +250,24 @@ with the PCI Express AER Root driver?
A: It could call the helper functions to enable AER in devices and
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.

View 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).
nommconf [X86] Disable use of MMCONFIG for PCI
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
enabled, this kernel boot option can be used to
disable the use of MSI interrupts system-wide.
@ -1828,7 +1831,7 @@ and is between 256 and 4096 characters. It is defined in the file
IRQ routing is enabled.
noacpi [X86] Do not use ACPI for IRQ routing
or for PCI scanning.
use_crs [X86] Use _CRS for PCI resource
nocrs [X86] Don't use _CRS for PCI resource
allocation.
routeirq Do IRQ routing for all PCI devices.
This is normally done in pci_enable_device(),
@ -1865,6 +1868,12 @@ and is between 256 and 4096 characters. It is defined in the file
PAGE_SIZE is used as alignment.
PCI-PCI bridge can be specified, if resource
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
Management.

View File

@ -122,7 +122,7 @@ static void eeh_enable_irq(struct pci_dev *dev)
* 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;
struct pci_driver *driver = dev->driver;
@ -130,19 +130,21 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
dev->error_state = pci_channel_io_frozen;
if (!driver)
return;
return 0;
eeh_disable_irq(dev);
if (!driver->err_handler ||
!driver->err_handler->error_detected)
return;
return 0;
rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
/* A driver that needs a reset trumps all others */
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
return 0;
}
/**
@ -153,7 +155,7 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
* Cumulative response passed back in "userdata".
*/
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;
struct pci_driver *driver = dev->driver;
@ -161,26 +163,28 @@ static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
if (!driver ||
!driver->err_handler ||
!driver->err_handler->mmio_enabled)
return;
return 0;
rc = driver->err_handler->mmio_enabled (dev);
/* A driver that needs a reset trumps all others */
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
return 0;
}
/**
* 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;
struct pci_driver *driver = dev->driver;
if (!driver)
return;
return 0;
dev->error_state = pci_channel_io_normal;
@ -188,35 +192,39 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
if (!driver->err_handler ||
!driver->err_handler->slot_reset)
return;
return 0;
rc = driver->err_handler->slot_reset(dev);
if ((*res == PCI_ERS_RESULT_NONE) ||
(*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
if (*res == PCI_ERS_RESULT_DISCONNECT &&
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
return 0;
}
/**
* 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;
dev->error_state = pci_channel_io_normal;
if (!driver)
return;
return 0;
eeh_enable_irq(dev);
if (!driver->err_handler ||
!driver->err_handler->resume)
return;
return 0;
driver->err_handler->resume(dev);
return 0;
}
/**
@ -226,22 +234,24 @@ static void eeh_report_resume(struct pci_dev *dev, void *userdata)
* dead, and that no further recovery attempts will be made on it.
*/
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;
dev->error_state = pci_channel_io_perm_failure;
if (!driver)
return;
return 0;
eeh_disable_irq(dev);
if (!driver->err_handler ||
!driver->err_handler->error_detected)
return;
return 0;
driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
return 0;
}
/* ------------------------------------------------------- */

View File

@ -130,6 +130,7 @@ extern void pci_iommu_alloc(void);
/* generic pci stuff */
#include <asm-generic/pci.h>
#define PCIBIOS_MAX_MEM_32 0xffffffff
#ifdef CONFIG_NUMA
/* Returns the node based on pci bus */

View File

@ -25,7 +25,7 @@
#define PCI_BIOS_IRQ_SCAN 0x2000
#define PCI_ASSIGN_ALL_BUSSES 0x4000
#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_HAS_IO_ECS 0x40000
#define PCI_NOASSIGN_ROMS 0x80000

View File

@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data)
struct acpi_resource_address64 addr;
acpi_status status;
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
return AE_OK;
status = resource_to_addr(acpi_res, &addr);
if (ACPI_SUCCESS(status))
info->res_num++;
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
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;
unsigned long flags;
struct resource *root;
if (info->res_num >= PCI_BUS_NUM_RESOURCES)
return AE_OK;
int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
status = resource_to_addr(acpi_res, &addr);
if (!ACPI_SUCCESS(status))
@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->end = res->start + addr.address_length - 1;
res->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)) {
printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
"from %s for %s\n", (unsigned long) res->start,
@ -217,7 +238,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
#endif
}
if (bus && (pci_probe & PCI_USE__CRS))
if (bus && !(pci_probe & PCI_NO_ROOT_CRS))
get_current_resources(device, busnum, domain, bus);
return bus;
}

View File

@ -101,7 +101,7 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
struct pci_root_info *info;
/* don't go for it if _CRS is used */
if (pci_probe & PCI_USE__CRS)
if (!(pci_probe & PCI_NO_ROOT_CRS))
return;
/* if only one root bus, don't need to anything */

View File

@ -515,8 +515,8 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
} else if (!strcmp(str, "use_crs")) {
pci_probe |= PCI_USE__CRS;
} else if (!strcmp(str, "nocrs")) {
pci_probe |= PCI_NO_ROOT_CRS;
return NULL;
} else if (!strcmp(str, "earlydump")) {
pci_early_dump_regs = 1;

View File

@ -266,6 +266,7 @@ config ACPI_DEBUG_FUNC_TRACE
config ACPI_PCI_SLOT
tristate "PCI slot detection driver"
depends on SYSFS
default n
help
This driver creates entries in /sys/bus/pci/slots/ for all PCI

View File

@ -2,10 +2,11 @@
# 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 \
irq.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
# Build PCI Express stuff if needed
obj-$(CONFIG_PCIEPORTBUS) += pcie/

View File

@ -66,6 +66,25 @@ EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
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

View File

@ -41,9 +41,14 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
void *alignf_data)
{
int i, ret = -ENOMEM;
resource_size_t max = -1;
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++) {
struct resource *r = bus->resource[i];
if (!r)
@ -62,7 +67,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
/* Ok, try it out.. */
ret = allocate_resource(r, res, size,
r->start ? : min,
-1, align,
max, align,
alignf, alignf_data);
if (ret == 0)
break;
@ -201,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus)
* Walk the given bus, including any bridged devices
* on buses under this bus. Call the provided callback
* 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)
{
struct pci_dev *dev;
struct pci_bus *bus;
struct list_head *next;
int retval;
bus = top;
down_read(&pci_bus_sem);
@ -231,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
/* Run device routines with the device locked */
down(&dev->dev.sem);
cb(dev, userdata);
retval = cb(dev, userdata);
up(&dev->dev.sem);
if (retval)
break;
}
up_read(&pci_bus_sem);
}

View File

@ -4,7 +4,7 @@
menuconfig HOTPLUG_PCI
tristate "Support for PCI Hotplug"
depends on PCI && HOTPLUG
depends on PCI && HOTPLUG && SYSFS
---help---
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
@ -41,7 +41,7 @@ config HOTPLUG_PCI_FAKE
config HOTPLUG_PCI_COMPAQ
tristate "Compaq PCI Hotplug driver"
depends on X86 && PCI_BIOS && PCI_LEGACY
depends on X86 && PCI_BIOS
help
Say Y here if you have a motherboard with a Compaq PCI Hotplug
controller.

View File

@ -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 struct hotplug_slot_ops acpi_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,

View File

@ -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 struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,

View File

@ -150,25 +150,25 @@ struct ctrl_reg { /* offset */
/* offsets to the controller registers based on the above structure layout */
enum ctrl_offsets {
SLOT_RST = offsetof(struct ctrl_reg, slot_RST),
SLOT_RST = offsetof(struct ctrl_reg, slot_RST),
SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable),
MISC = offsetof(struct ctrl_reg, misc),
LED_CONTROL = offsetof(struct ctrl_reg, led_control),
INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear),
INT_MASK = offsetof(struct ctrl_reg, int_mask),
CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0),
INT_MASK = offsetof(struct ctrl_reg, int_mask),
CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0),
CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1),
CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1),
GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB),
NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input),
GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB),
NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input),
CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3),
CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4),
CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5),
CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6),
CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7),
CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8),
SLOT_MASK = offsetof(struct ctrl_reg, slot_mask),
CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9),
SLOT_MASK = offsetof(struct ctrl_reg, slot_mask),
CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9),
CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10),
CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11),
SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR),
@ -190,7 +190,9 @@ struct hrt {
u32 reserved2;
} __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 {
SIG0 = offsetof(struct hrt, sig0),
SIG1 = offsetof(struct hrt, sig1),
@ -217,18 +219,20 @@ struct slot_rt {
u16 pre_mem_length;
} __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 {
DEV_FUNC = offsetof(struct slot_rt, dev_func),
PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
MAX_BUS = offsetof(struct slot_rt, max_bus),
IO_BASE = offsetof(struct slot_rt, io_base),
IO_LENGTH = offsetof(struct slot_rt, io_length),
MEM_BASE = offsetof(struct slot_rt, mem_base),
MEM_LENGTH = offsetof(struct slot_rt, mem_length),
PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
MAX_BUS = offsetof(struct slot_rt, max_bus),
IO_BASE = offsetof(struct slot_rt, io_base),
IO_LENGTH = offsetof(struct slot_rt, io_length),
MEM_BASE = offsetof(struct slot_rt, mem_base),
MEM_LENGTH = offsetof(struct slot_rt, mem_length),
PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
};
struct pci_func {
@ -286,8 +290,8 @@ struct event_info {
struct controller {
struct controller *next;
u32 ctrl_int_comp;
struct mutex crit_sect; /* critical section mutex */
void __iomem *hpc_reg; /* cookie for our pci controller location */
struct mutex crit_sect; /* critical section mutex */
void __iomem *hpc_reg; /* cookie for our pci controller location */
struct pci_resource *mem_head;
struct pci_resource *p_mem_head;
struct pci_resource *io_head;
@ -299,7 +303,7 @@ struct controller {
u8 next_event;
u8 interrupt;
u8 cfgspc_irq;
u8 bus; /* bus number for the pci hotplug controller */
u8 bus; /* bus number for the pci hotplug controller */
u8 rev;
u8 slot_device_offset;
u8 first_slot;
@ -401,46 +405,57 @@ struct resource_lists {
/* debugfs functions for the hotplug controller info */
extern void cpqhp_initialize_debugfs (void);
extern void cpqhp_shutdown_debugfs (void);
extern void cpqhp_create_debugfs_files (struct controller *ctrl);
extern void cpqhp_remove_debugfs_files (struct controller *ctrl);
extern void cpqhp_initialize_debugfs(void);
extern void cpqhp_shutdown_debugfs(void);
extern void cpqhp_create_debugfs_files(struct controller *ctrl);
extern void cpqhp_remove_debugfs_files(struct controller *ctrl);
/* controller functions */
extern void cpqhp_pushbutton_thread (unsigned long event_pointer);
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_event_start_thread (void);
extern void cpqhp_event_stop_thread (void);
extern struct pci_func *cpqhp_slot_create (unsigned char busnumber);
extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index);
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);
extern void cpqhp_pushbutton_thread(unsigned long event_pointer);
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_event_start_thread(void);
extern void cpqhp_event_stop_thread(void);
extern struct pci_func *cpqhp_slot_create(unsigned char busnumber);
extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
unsigned char index);
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 */
extern int cpqhp_resource_sort_and_combine (struct pci_resource **head);
/* pci functions */
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_save_config (struct controller *ctrl, int busnumber, int is_hot_plug);
extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func);
extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func);
extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func);
extern int cpqhp_save_slot_config (struct controller *ctrl, 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);
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_save_config(struct controller *ctrl, int busnumber,
int is_hot_plug);
extern int cpqhp_save_base_addr_length(struct controller *ctrl,
struct pci_func *func);
extern int cpqhp_save_used_resources(struct controller *ctrl,
struct pci_func *func);
extern int cpqhp_configure_board(struct controller *ctrl,
struct pci_func *func);
extern int cpqhp_save_slot_config(struct controller *ctrl,
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 */
extern int cpqhp_debug;
extern int cpqhp_legacy_mode;
extern struct controller *cpqhp_ctrl_list;
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 */
extern u8 cpqhp_nic_irq;
@ -449,7 +464,7 @@ extern u8 cpqhp_disk_irq;
/* 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);
}
@ -458,9 +473,9 @@ static inline char *slot_name(struct slot *slot)
* return_resource
*
* 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)
return;
@ -471,7 +486,7 @@ static inline void return_resource(struct pci_resource **head, struct pci_resour
static inline void set_SOGO(struct controller *ctrl)
{
u16 misc;
misc = readw(ctrl->hpc_reg + MISC);
misc = (misc | 0x0001) & 0xFFFB;
writew(misc, ctrl->hpc_reg + MISC);
@ -481,7 +496,7 @@ static inline void set_SOGO(struct controller *ctrl)
static inline void amber_LED_on(struct controller *ctrl, u8 slot)
{
u32 led_control;
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control |= (0x01010000L << slot);
writel(led_control, ctrl->hpc_reg + LED_CONTROL);
@ -491,7 +506,7 @@ static inline void amber_LED_on(struct controller *ctrl, u8 slot)
static inline void amber_LED_off(struct controller *ctrl, u8 slot)
{
u32 led_control;
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control &= ~(0x01010000L << slot);
writel(led_control, ctrl->hpc_reg + LED_CONTROL);
@ -504,7 +519,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot)
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control &= (0x01010000L << slot);
return led_control ? 1 : 0;
}
@ -512,7 +527,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot)
static inline void green_LED_on(struct controller *ctrl, u8 slot)
{
u32 led_control;
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control |= 0x0101L << slot;
writel(led_control, ctrl->hpc_reg + LED_CONTROL);
@ -521,7 +536,7 @@ static inline void green_LED_on(struct controller *ctrl, u8 slot)
static inline void green_LED_off(struct controller *ctrl, u8 slot)
{
u32 led_control;
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control &= ~(0x0101L << slot);
writel(led_control, ctrl->hpc_reg + LED_CONTROL);
@ -531,7 +546,7 @@ static inline void green_LED_off(struct controller *ctrl, u8 slot)
static inline void green_LED_blink(struct controller *ctrl, u8 slot)
{
u32 led_control;
led_control = readl(ctrl->hpc_reg + LED_CONTROL);
led_control &= ~(0x0101L << slot);
led_control |= (0x0001L << slot);
@ -575,22 +590,21 @@ static inline u8 read_slot_enable(struct controller *ctrl)
}
/*
/**
* get_controller_speed - find the current frequency/mode of controller.
*
* @ctrl: controller to get frequency/mode for.
*
* Returns controller speed.
*
*/
static inline u8 get_controller_speed(struct controller *ctrl)
{
u8 curr_freq;
u16 misc;
u16 misc;
if (ctrl->pcix_support) {
curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
if ((curr_freq & 0xB0) == 0xB0)
if ((curr_freq & 0xB0) == 0xB0)
return PCI_SPEED_133MHz_PCIX;
if ((curr_freq & 0xA0) == 0xA0)
return PCI_SPEED_100MHz_PCIX;
@ -602,19 +616,18 @@ static inline u8 get_controller_speed(struct controller *ctrl)
return PCI_SPEED_33MHz;
}
misc = readw(ctrl->hpc_reg + MISC);
return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
misc = readw(ctrl->hpc_reg + MISC);
return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
}
/*
/**
* get_adapter_speed - find the max supported frequency/mode of adapter.
*
* @ctrl: hotplug controller.
* @hp_slot: hotplug slot where adapter is installed.
*
* Returns adapter speed.
*
*/
static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot)
{
@ -672,7 +685,8 @@ static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot)
}
static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot)
static inline int cpq_get_latch_status(struct controller *ctrl,
struct slot *slot)
{
u32 status;
u8 hp_slot;
@ -687,7 +701,8 @@ static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slo
}
static inline int get_presence_status(struct controller *ctrl, struct slot *slot)
static inline int get_presence_status(struct controller *ctrl,
struct slot *slot)
{
int presence_save = 0;
u8 hp_slot;
@ -696,7 +711,8 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot
hp_slot = slot->device - ctrl->slot_device_offset;
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;
}
@ -718,5 +734,12 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl)
return retval;
}
#endif
#include <asm/pci_x86.h>
static inline int cpqhp_routing_table_length(void)
{
BUG_ON(cpqhp_routing_table == NULL);
return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) /
sizeof(struct irq_info));
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -81,14 +81,15 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
if (change & (0x1L << hp_slot)) {
/**********************************
/*
* this one changed.
**********************************/
*/
func = cpqhp_slot_find(ctrl->bus,
(hp_slot + ctrl->slot_device_offset), 0);
/* this is the structure that tells the worker thread
*what to do */
* what to do
*/
taskInfo = &(ctrl->event_queue[ctrl->next_event]);
ctrl->next_event = (ctrl->next_event + 1) % 10;
taskInfo->hp_slot = hp_slot;
@ -100,17 +101,17 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
/**********************************
/*
* Switch opened
**********************************/
*/
func->switch_save = 0;
taskInfo->event_type = INT_SWITCH_OPEN;
} else {
/**********************************
/*
* Switch closed
**********************************/
*/
func->switch_save = 0x10;
@ -131,9 +132,8 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device)
{
struct slot *slot = ctrl->slot;
while (slot && (slot->device != device)) {
while (slot && (slot->device != device))
slot = slot->next;
}
return slot;
}
@ -152,17 +152,17 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
if (!change)
return 0;
/**********************************
/*
* Presence Change
**********************************/
*/
dbg("cpqsbd: Presence/Notify input change.\n");
dbg(" Changed bits are 0x%4.4x\n", change );
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
if (change & (0x0101 << hp_slot)) {
/**********************************
/*
* this one changed.
**********************************/
*/
func = cpqhp_slot_find(ctrl->bus,
(hp_slot + ctrl->slot_device_offset), 0);
@ -177,22 +177,23 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
return 0;
/* If the switch closed, must be a button
* If not in button mode, nevermind */
* If not in button mode, nevermind
*/
if (func->switch_save && (ctrl->push_button == 1)) {
temp_word = ctrl->ctrl_int_comp >> 16;
temp_byte = (temp_word >> hp_slot) & 0x01;
temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02;
if (temp_byte != func->presence_save) {
/**************************************
/*
* button Pressed (doesn't do anything)
**************************************/
*/
dbg("hp_slot %d button pressed\n", hp_slot);
taskInfo->event_type = INT_BUTTON_PRESS;
} else {
/**********************************
/*
* button Released - TAKE ACTION!!!!
**********************************/
*/
dbg("hp_slot %d button released\n", hp_slot);
taskInfo->event_type = INT_BUTTON_RELEASE;
@ -210,7 +211,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
}
} else {
/* Switch is open, assume a presence change
* Save the presence state */
* Save the presence state
*/
temp_word = ctrl->ctrl_int_comp >> 16;
func->presence_save = (temp_word >> hp_slot) & 0x01;
func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
@ -241,17 +243,17 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl)
if (!change)
return 0;
/**********************************
/*
* power fault
**********************************/
*/
info("power fault interrupt\n");
for (hp_slot = 0; hp_slot < 6; hp_slot++) {
if (change & (0x01 << hp_slot)) {
/**********************************
/*
* this one changed.
**********************************/
*/
func = cpqhp_slot_find(ctrl->bus,
(hp_slot + ctrl->slot_device_offset), 0);
@ -262,16 +264,16 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl)
rc++;
if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) {
/**********************************
/*
* power fault Cleared
**********************************/
*/
func->status = 0x00;
taskInfo->event_type = INT_POWER_FAULT_CLEAR;
} else {
/**********************************
/*
* power fault
**********************************/
*/
taskInfo->event_type = INT_POWER_FAULT;
if (ctrl->rev < 4) {
@ -432,13 +434,15 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h
/* If we got here, there the bridge requires some of the resource, but
* we may be able to split some off of the front */
* we may be able to split some off of the front
*/
node = *head;
if (node->length & (alignment -1)) {
/* this one isn't an aligned length, so we'll make a new entry
* and split it up. */
* and split it up.
*/
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
if (!split_node)
@ -544,10 +548,10 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
if (!(*head))
return NULL;
if ( cpqhp_resource_sort_and_combine(head) )
if (cpqhp_resource_sort_and_combine(head))
return NULL;
if ( sort_by_size(head) )
if (sort_by_size(head))
return NULL;
for (node = *head; node; node = node->next) {
@ -556,7 +560,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
if (node->base & (size - 1)) {
/* this one isn't base aligned properly
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
temp_dword = (node->base | (size-1)) + 1;
/* Short circuit if adjusted size is too small */
@ -581,7 +586,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
/* Don't need to check if too small since we already did */
if (node->length > size) {
/* this one is longer than we need
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
if (!split_node)
@ -601,7 +607,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size
continue;
/* If we got here, then it is the right size
* Now take it out of the list and break */
* Now take it out of the list and break
*/
if (*head == node) {
*head = node->next;
} else {
@ -642,14 +649,16 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz
return NULL;
for (max = *head; max; max = max->next) {
/* If not big enough we could probably just bail,
* instead we'll continue to the next. */
/* If not big enough we could probably just bail,
* instead we'll continue to the next.
*/
if (max->length < size)
continue;
if (max->base & (size - 1)) {
/* this one isn't base aligned properly
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
temp_dword = (max->base | (size-1)) + 1;
/* Short circuit if adjusted size is too small */
@ -672,7 +681,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz
if ((max->base + max->length) & (size - 1)) {
/* this one isn't end aligned properly at the top
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
if (!split_node)
@ -744,7 +754,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
if (node->base & (size - 1)) {
dbg("%s: not aligned\n", __func__);
/* this one isn't base aligned properly
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
temp_dword = (node->base | (size-1)) + 1;
/* Short circuit if adjusted size is too small */
@ -769,7 +780,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
if (node->length > size) {
dbg("%s: too big\n", __func__);
/* this one is longer than we need
* so we'll make a new entry and split it up */
* so we'll make a new entry and split it up
*/
split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
if (!split_node)
@ -886,19 +898,19 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
u32 Diff;
u32 temp_dword;
misc = readw(ctrl->hpc_reg + MISC);
/***************************************
/*
* Check to see if it was our interrupt
***************************************/
*/
if (!(misc & 0x000C)) {
return IRQ_NONE;
}
if (misc & 0x0004) {
/**********************************
/*
* Serial Output interrupt Pending
**********************************/
*/
/* Clear the interrupt */
misc |= 0x0004;
@ -961,11 +973,8 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
struct pci_func *next;
new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
if (new_slot == NULL) {
/* I'm not dead yet!
* You will be. */
if (new_slot == NULL)
return new_slot;
}
new_slot->next = NULL;
new_slot->configured = 1;
@ -996,10 +1005,8 @@ static int slot_remove(struct pci_func * old_slot)
return 1;
next = cpqhp_slot_list[old_slot->bus];
if (next == NULL) {
if (next == NULL)
return 1;
}
if (next == old_slot) {
cpqhp_slot_list[old_slot->bus] = old_slot->next;
@ -1008,9 +1015,8 @@ static int slot_remove(struct pci_func * old_slot)
return 0;
}
while ((next->next != old_slot) && (next->next != NULL)) {
while ((next->next != old_slot) && (next->next != NULL))
next = next->next;
}
if (next->next == old_slot) {
next->next = old_slot->next;
@ -1040,9 +1046,8 @@ static int bridge_slot_remove(struct pci_func *bridge)
for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
next = cpqhp_slot_list[tempBus];
while (!slot_remove(next)) {
while (!slot_remove(next))
next = cpqhp_slot_list[tempBus];
}
}
next = cpqhp_slot_list[bridge->bus];
@ -1130,39 +1135,43 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
u16 reg16;
u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
if (ctrl->speed == adapter_speed)
return 0;
/* We don't allow freq/mode changes if we find another adapter running
* in another slot on this controller */
* in another slot on this controller
*/
for(slot = ctrl->slot; slot; slot = slot->next) {
if (slot->device == (hp_slot + ctrl->slot_device_offset))
if (slot->device == (hp_slot + ctrl->slot_device_offset))
continue;
if (!slot->hotplug_slot || !slot->hotplug_slot->info)
continue;
if (slot->hotplug_slot->info->adapter_status == 0)
if (slot->hotplug_slot->info->adapter_status == 0)
continue;
/* If another adapter is running on the same segment but at a
* lower speed/mode, we allow the new adapter to function at
* this rate if supported */
if (ctrl->speed < adapter_speed)
* this rate if supported
*/
if (ctrl->speed < adapter_speed)
return 0;
return 1;
}
/* If the controller doesn't support freq/mode changes and the
* controller is running at a higher mode, we bail */
* controller is running at a higher mode, we bail
*/
if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
return 1;
/* But we allow the adapter to run at a lower rate if possible */
if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
return 0;
/* We try to set the max speed supported by both the adapter and
* controller */
* controller
*/
if (ctrl->speed_capability < adapter_speed) {
if (ctrl->speed == ctrl->speed_capability)
return 0;
@ -1171,22 +1180,22 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE);
set_SOGO(ctrl);
set_SOGO(ctrl);
wait_for_ctrl_irq(ctrl);
if (adapter_speed != PCI_SPEED_133MHz_PCIX)
reg = 0xF5;
else
reg = 0xF4;
reg = 0xF4;
pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ);
reg16 &= ~0x000F;
switch(adapter_speed) {
case(PCI_SPEED_133MHz_PCIX):
case(PCI_SPEED_133MHz_PCIX):
reg = 0x75;
reg16 |= 0xB;
reg16 |= 0xB;
break;
case(PCI_SPEED_100MHz_PCIX):
reg = 0x74;
@ -1203,48 +1212,48 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
default: /* 33MHz PCI 2.2 */
reg = 0x71;
break;
}
reg16 |= 0xB << 12;
writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ);
mdelay(5);
mdelay(5);
/* Reenable interrupts */
writel(0, ctrl->hpc_reg + INT_MASK);
pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
/* Restart state machine */
reg = ~0xF;
pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
/* Only if mode change...*/
if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz)))
set_SOGO(ctrl);
wait_for_ctrl_irq(ctrl);
mdelay(1100);
/* Restore LED/Slot state */
writel(leds, ctrl->hpc_reg + LED_CONTROL);
writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE);
set_SOGO(ctrl);
wait_for_ctrl_irq(ctrl);
ctrl->speed = adapter_speed;
slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
info("Successfully changed frequency/mode for adapter in slot %d\n",
info("Successfully changed frequency/mode for adapter in slot %d\n",
slot->number);
return 0;
}
/* the following routines constitute the bulk of the
hotplug controller logic
/* the following routines constitute the bulk of the
* hotplug controller logic
*/
@ -1268,17 +1277,17 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
hp_slot = func->device - ctrl->slot_device_offset;
if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) {
/**********************************
* The switch is open.
**********************************/
/*
* The switch is open.
*/
if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot))
rc = INTERLOCK_OPEN;
} else if (is_slot_enabled (ctrl, hp_slot)) {
/**********************************
* The board is already on
**********************************/
/*
* The board is already on
*/
else if (is_slot_enabled (ctrl, hp_slot))
rc = CARD_FUNCTIONING;
} else {
else {
mutex_lock(&ctrl->crit_sect);
/* turn on board without attaching to the bus */
@ -1299,7 +1308,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
/* Wait for SOBS to be unset */
wait_for_ctrl_irq (ctrl);
adapter_speed = get_adapter_speed(ctrl, hp_slot);
if (ctrl->speed != adapter_speed)
if (set_controller_speed(ctrl, adapter_speed, hp_slot))
@ -1352,7 +1361,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
* Get slot won't work for devices behind
* bridges, but in this case it will always be
* called for the "base" bus/dev/func of an
* adapter. */
* adapter.
*/
mutex_lock(&ctrl->crit_sect);
@ -1377,7 +1387,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
* Get slot won't work for devices behind bridges, but
* in this case it will always be called for the "base"
* bus/dev/func of an adapter. */
* bus/dev/func of an adapter.
*/
mutex_lock(&ctrl->crit_sect);
@ -1434,7 +1445,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
/* Change bits in slot power register to force another shift out
* NOTE: this is to work around the timer bug */
* NOTE: this is to work around the timer bug
*/
temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
@ -1443,12 +1455,12 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
/* Wait for SOBS to be unset */
wait_for_ctrl_irq (ctrl);
adapter_speed = get_adapter_speed(ctrl, hp_slot);
if (ctrl->speed != adapter_speed)
if (set_controller_speed(ctrl, adapter_speed, hp_slot))
rc = WRONG_BUS_FREQUENCY;
/* turn off board without attaching to the bus */
disable_slot_power (ctrl, hp_slot);
@ -1461,7 +1473,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
if (rc)
return rc;
p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/* turn on board and blink green LED */
@ -1521,7 +1533,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
}
/* All F's is an empty slot or an invalid board */
if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */
if (temp_register != 0xFFFFFFFF) {
res_lists.io_head = ctrl->io_head;
res_lists.mem_head = ctrl->mem_head;
res_lists.p_mem_head = ctrl->p_mem_head;
@ -1570,9 +1582,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
index = 0;
do {
new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
if (new_slot && !new_slot->pci_dev) {
if (new_slot && !new_slot->pci_dev)
cpqhp_configure_device(ctrl, new_slot);
}
} while (new_slot);
mutex_lock(&ctrl->crit_sect);
@ -1859,12 +1870,12 @@ static void interrupt_event_handler(struct controller *ctrl)
info(msg_button_on, p_slot->number);
}
mutex_lock(&ctrl->crit_sect);
dbg("blink green LED and turn off amber\n");
amber_LED_off (ctrl, hp_slot);
green_LED_blink (ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
@ -1958,7 +1969,7 @@ void cpqhp_pushbutton_thread(unsigned long slot)
if (cpqhp_process_SI(ctrl, func) != 0) {
amber_LED_on(ctrl, hp_slot);
green_LED_off(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
@ -2079,7 +2090,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
struct pci_bus *pci_bus = ctrl->pci_bus;
int physical_slot=0;
device = func->device;
device = func->device;
func = cpqhp_slot_find(ctrl->bus, device, index++);
p_slot = cpqhp_find_slot(ctrl, device);
if (p_slot) {
@ -2113,9 +2124,8 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
/* If the VGA Enable bit is set, remove isn't
* supported */
if (BCR & PCI_BRIDGE_CTL_VGA) {
if (BCR & PCI_BRIDGE_CTL_VGA)
rc = REMOVE_NOT_SUPPORTED;
}
}
}
@ -2183,67 +2193,67 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num)
num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f;
switch (test_num) {
case 1:
/* Do stuff here! */
case 1:
/* Do stuff here! */
/* Do that funky LED thing */
/* so we can restore them later */
save_LED = readl(ctrl->hpc_reg + LED_CONTROL);
work_LED = 0x01010101;
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
/* Do that funky LED thing */
/* so we can restore them later */
save_LED = readl(ctrl->hpc_reg + LED_CONTROL);
work_LED = 0x01010101;
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
work_LED = 0x01010000;
work_LED = 0x01010000;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
work_LED = 0x00000101;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
work_LED = 0x01010000;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
for (loop = 0; loop < num_of_slots; loop++) {
set_SOGO(ctrl);
/* Wait for SOGO interrupt */
wait_for_ctrl_irq (ctrl);
/* Get ready for next iteration */
long_delay((3*HZ)/10);
work_LED = work_LED >> 16;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
work_LED = 0x00000101;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
switch_leds(ctrl, num_of_slots, &work_LED, 0);
switch_leds(ctrl, num_of_slots, &work_LED, 1);
work_LED = 0x01010000;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
for (loop = 0; loop < num_of_slots; loop++) {
set_SOGO(ctrl);
/* Wait for SOGO interrupt */
wait_for_ctrl_irq (ctrl);
/* Get ready for next iteration */
long_delay((3*HZ)/10);
work_LED = work_LED >> 16;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
set_SOGO(ctrl);
/* Wait for SOGO interrupt */
wait_for_ctrl_irq (ctrl);
/* Get ready for next iteration */
long_delay((3*HZ)/10);
work_LED = work_LED << 16;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
work_LED = work_LED << 1;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
}
/* put it back the way it was */
writel(save_LED, ctrl->hpc_reg + LED_CONTROL);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
/* Wait for SOGO interrupt */
wait_for_ctrl_irq (ctrl);
break;
case 2:
/* Do other stuff here! */
break;
case 3:
/* and more... */
break;
/* Get ready for next iteration */
long_delay((3*HZ)/10);
work_LED = work_LED << 16;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
work_LED = work_LED << 1;
writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
}
/* put it back the way it was */
writel(save_LED, ctrl->hpc_reg + LED_CONTROL);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq (ctrl);
break;
case 2:
/* Do other stuff here! */
break;
case 3:
/* and more... */
break;
}
return 0;
}
@ -2312,9 +2322,9 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func
while ((function < max_functions) && (!stop_it)) {
pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
if (ID == 0xFFFFFFFF) { /* There's nothing there. */
if (ID == 0xFFFFFFFF) {
function++;
} else { /* There's something there */
} else {
/* Setup slot structure. */
new_slot = cpqhp_slot_create(func->bus);
@ -2339,8 +2349,8 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func
/*
Configuration logic that involves the hotplug data structures and
their bookkeeping
* Configuration logic that involves the hotplug data structures and
* their bookkeeping
*/
@ -2393,7 +2403,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
if (rc)
return rc;
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
/* set Primary bus */
dbg("set Primary bus = %d\n", func->bus);
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
@ -2484,7 +2494,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
temp_resources.irqs = &irqs;
/* Make copies of the nodes we are going to pass down so that
* if there is a problem,we can just use these to free resources */
* if there is a problem,we can just use these to free resources
*/
hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL);
hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL);
hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL);
@ -2556,7 +2567,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
/* Adjust this to compensate for extra adjustment in first loop */
/* Adjust this to compensate for extra adjustment in first loop
*/
irqs.barber_pole--;
rc = 0;
@ -2917,27 +2929,26 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
} /* End of base register loop */
if (cpqhp_legacy_mode) {
/* Figure out which interrupt pin this function uses */
rc = pci_bus_read_config_byte (pci_bus, devfn,
rc = pci_bus_read_config_byte (pci_bus, devfn,
PCI_INTERRUPT_PIN, &temp_byte);
/* If this function needs an interrupt and we are behind
* a bridge and the pin is tied to something that's
* alread mapped, set this one the same */
if (temp_byte && resources->irqs &&
(resources->irqs->valid_INT &
if (temp_byte && resources->irqs &&
(resources->irqs->valid_INT &
(0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
/* We have to share with something already set up */
IRQ = resources->irqs->interrupt[(temp_byte +
IRQ = resources->irqs->interrupt[(temp_byte +
resources->irqs->barber_pole - 1) & 0x03];
} else {
/* Program IRQ based on card type */
rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
if (class_code == PCI_BASE_CLASS_STORAGE) {
if (class_code == PCI_BASE_CLASS_STORAGE)
IRQ = cpqhp_disk_irq;
} else {
else
IRQ = cpqhp_nic_irq;
}
}
/* IRQ Line */

View File

@ -94,12 +94,13 @@ static u8 evbuffer[1024];
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
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!!!
@ -113,7 +114,7 @@ static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail)
if ((*used + 1) > *avail)
return(1);
*((u8*)*p_buffer) = value;
tByte = (u8**)p_buffer;
(*tByte)++;
@ -170,10 +171,10 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
unsigned long flags;
int op = operation;
int ret_val;
if (!compaq_int15_entry_point)
return -ENODEV;
spin_lock_irqsave(&int15_lock, flags);
__asm__ (
"xorl %%ebx,%%ebx\n" \
@ -187,7 +188,7 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
"D" (buffer), "m" (compaq_int15_entry_point)
: "%ebx", "%edx");
spin_unlock_irqrestore(&int15_lock, flags);
return((ret_val & 0xFF00) >> 8);
}
@ -210,14 +211,16 @@ static int load_HRT (void __iomem *rom_start)
available = 1024;
// Now load the EV
/* Now load the EV */
temp_dword = available;
rc = access_EV(READ_EV, "CQTHPS", evbuffer, &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;
rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
@ -263,13 +266,13 @@ static u32 store_HRT (void __iomem *rom_start)
p_EV_header = (struct ev_hrt_header *) pFill;
ctrl = cpqhp_ctrl_list;
// The revision of this structure
/* The revision of this structure */
rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
if (rc)
return(rc);
// The number of controllers
/* The number of controllers */
rc = add_byte( &pFill, 1, &usedbytes, &available);
if (rc)
return(rc);
@ -279,27 +282,27 @@ static u32 store_HRT (void __iomem *rom_start)
numCtrl++;
// The bus number
/* The bus number */
rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
if (rc)
return(rc);
// The device Number
/* The device Number */
rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
if (rc)
return(rc);
// The function Number
/* The function Number */
rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
if (rc)
return(rc);
// Skip the number of available entries
/* Skip the number of available entries */
rc = add_dword( &pFill, 0, &usedbytes, &available);
if (rc)
return(rc);
// Figure out memory Available
/* Figure out memory Available */
resNode = ctrl->mem_head;
@ -308,12 +311,12 @@ static u32 store_HRT (void __iomem *rom_start)
while (resNode) {
loop ++;
// base
/* base */
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
if (rc)
return(rc);
// length
/* length */
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
if (rc)
return(rc);
@ -321,10 +324,10 @@ static u32 store_HRT (void __iomem *rom_start)
resNode = resNode->next;
}
// Fill in the number of entries
/* Fill in the number of entries */
p_ev_ctrl->mem_avail = loop;
// Figure out prefetchable memory Available
/* Figure out prefetchable memory Available */
resNode = ctrl->p_mem_head;
@ -333,12 +336,12 @@ static u32 store_HRT (void __iomem *rom_start)
while (resNode) {
loop ++;
// base
/* base */
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
if (rc)
return(rc);
// length
/* length */
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
if (rc)
return(rc);
@ -346,10 +349,10 @@ static u32 store_HRT (void __iomem *rom_start)
resNode = resNode->next;
}
// Fill in the number of entries
/* Fill in the number of entries */
p_ev_ctrl->p_mem_avail = loop;
// Figure out IO Available
/* Figure out IO Available */
resNode = ctrl->io_head;
@ -358,12 +361,12 @@ static u32 store_HRT (void __iomem *rom_start)
while (resNode) {
loop ++;
// base
/* base */
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
if (rc)
return(rc);
// length
/* length */
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
if (rc)
return(rc);
@ -371,10 +374,10 @@ static u32 store_HRT (void __iomem *rom_start)
resNode = resNode->next;
}
// Fill in the number of entries
/* Fill in the number of entries */
p_ev_ctrl->io_avail = loop;
// Figure out bus Available
/* Figure out bus Available */
resNode = ctrl->bus_head;
@ -383,12 +386,12 @@ static u32 store_HRT (void __iomem *rom_start)
while (resNode) {
loop ++;
// base
/* base */
rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
if (rc)
return(rc);
// length
/* length */
rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
if (rc)
return(rc);
@ -396,15 +399,15 @@ static u32 store_HRT (void __iomem *rom_start)
resNode = resNode->next;
}
// Fill in the number of entries
/* Fill in the number of entries */
p_ev_ctrl->bus_avail = loop;
ctrl = ctrl->next;
}
p_EV_header->num_of_ctrl = numCtrl;
// Now store the EV
/* Now store the EV */
temp_dword = usedbytes;
@ -449,20 +452,21 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
struct ev_hrt_header *p_EV_header;
if (!evbuffer_init) {
// Read the resource list information in from NVRAM
/* Read the resource list information in from NVRAM */
if (load_HRT(rom_start))
memset (evbuffer, 0, 1024);
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;
// The following code is for systems where version 1.0 of this
// driver has been loaded, but doesn't support the hardware.
// In that case, the driver would incorrectly store something
// in NVRAM.
/* The following code is for systems where version 1.0 of this
* driver has been loaded, but doesn't support the hardware.
* In that case, the driver would incorrectly store something
* in NVRAM.
*/
if ((p_EV_header->Version == 2) ||
((p_EV_header->Version == 1) && !ctrl->push_flag)) {
p_byte = &(p_EV_header->next);
@ -479,7 +483,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
function = p_ev_ctrl->function;
while ((bus != ctrl->bus) ||
(device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
(device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
(function != PCI_FUNC(ctrl->pci_dev->devfn))) {
nummem = p_ev_ctrl->mem_avail;
numpmem = p_ev_ctrl->p_mem_avail;
@ -491,7 +495,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return 2;
// Skip forward to the next entry
/* Skip forward to the next entry */
p_byte += (nummem + numpmem + numio + numbus) * 8;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
@ -629,8 +633,9 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
ctrl->bus_head = bus_node;
}
// If all of the following fail, we don't have any resources for
// hot plug add
/* If all of the following fail, we don't have any resources for
* hot plug add
*/
rc = 1;
rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
@ -640,14 +645,14 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
if (rc)
return(rc);
} else {
if ((evbuffer[0] != 0) && (!ctrl->push_flag))
if ((evbuffer[0] != 0) && (!ctrl->push_flag))
return 1;
}
return 0;
}
int compaq_nvram_store (void __iomem *rom_start)
{
int rc = 1;

File diff suppressed because it is too large Load Diff

View File

@ -1318,7 +1318,6 @@ error:
}
struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
.owner = THIS_MODULE,
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = ibmphp_disable_slot,
@ -1421,3 +1420,4 @@ static void __exit ibmphp_exit(void)
}
module_init(ibmphp_init);
module_exit(ibmphp_exit);

View File

@ -347,125 +347,129 @@ static struct pci_slot_attribute hotplug_slot_attr_test = {
.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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if ((slot->ops->enable_slot) ||
(slot->ops->disable_slot) ||
(slot->ops->get_power_status))
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if ((slot->ops->set_attention_status) ||
(slot->ops->get_attention_status))
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if (slot->ops->get_latch_status)
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if (slot->ops->get_adapter_status)
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if (slot->ops->get_max_bus_speed)
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if (slot->ops->get_cur_bus_speed)
return 0;
return -ENOENT;
return true;
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;
if ((!slot) || (!slot->ops))
return -ENODEV;
return false;
if (slot->ops->hardware_test)
return 0;
return -ENOENT;
return true;
return false;
}
static int fs_add_slot(struct pci_slot *slot)
{
int retval = 0;
if (has_power_file(slot) == 0) {
retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
/* Create symbolic link to the hotplug driver module */
pci_hp_create_module_link(slot);
if (has_power_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_power.attr);
if (retval)
goto exit_power;
}
if (has_attention_file(slot) == 0) {
if (has_attention_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_attention.attr);
if (retval)
goto exit_attention;
}
if (has_latch_file(slot) == 0) {
if (has_latch_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_latch.attr);
if (retval)
goto exit_latch;
}
if (has_adapter_file(slot) == 0) {
if (has_adapter_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_presence.attr);
if (retval)
goto exit_adapter;
}
if (has_max_bus_speed_file(slot) == 0) {
if (has_max_bus_speed_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_max_bus_speed.attr);
&hotplug_slot_attr_max_bus_speed.attr);
if (retval)
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,
&hotplug_slot_attr_cur_bus_speed.attr);
&hotplug_slot_attr_cur_bus_speed.attr);
if (retval)
goto exit_cur_speed;
}
if (has_test_file(slot) == 0) {
if (has_test_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_test.attr);
if (retval)
@ -475,55 +479,61 @@ static int fs_add_slot(struct pci_slot *slot)
goto exit;
exit_test:
if (has_cur_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
if (has_cur_bus_speed_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_cur_bus_speed.attr);
exit_cur_speed:
if (has_max_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
if (has_max_bus_speed_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_max_bus_speed.attr);
exit_max_speed:
if (has_adapter_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if (has_adapter_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_presence.attr);
exit_adapter:
if (has_latch_file(slot) == 0)
if (has_latch_file(slot))
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
exit_latch:
if (has_attention_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
if (has_attention_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_attention.attr);
exit_attention:
if (has_power_file(slot) == 0)
if (has_power_file(slot))
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
exit_power:
pci_hp_remove_module_link(slot);
exit:
return retval;
}
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);
if (has_attention_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
if (has_attention_file(slot))
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);
if (has_adapter_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if (has_adapter_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_presence.attr);
if (has_max_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
if (has_max_bus_speed_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_max_bus_speed.attr);
if (has_cur_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
if (has_cur_bus_speed_file(slot))
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);
pci_hp_remove_module_link(slot);
}
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
* @slot: pointer to the &struct hotplug_slot to register
* @slot_nr: slot number
* @devnr: device number
* @name: name registered with kobject core
*
* Registers a hotplug slot with the pci hotplug subsystem, which will allow
@ -551,8 +561,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
*
* Returns 0 if successful, anything else for an error.
*/
int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
const char *name)
int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
int devnr, const char *name,
struct module *owner, const char *mod_name)
{
int result;
struct pci_slot *pci_slot;
@ -567,14 +578,16 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
return -EINVAL;
}
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
* driver and call it here again. If we've already created the
* 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)) {
result = PTR_ERR(pci_slot);
goto out;
@ -684,6 +697,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, 0644);
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_change_slot_info);

View File

@ -81,7 +81,6 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
unsigned long last_emi_toggle;
struct delayed_work work; /* work for button event */
struct mutex lock;
};
@ -203,8 +202,6 @@ struct hpc_ops {
int (*set_attention_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_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_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);

View File

@ -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 struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.owner = THIS_MODULE,
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
@ -85,99 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_cur_bus_speed = get_cur_bus_speed,
};
/*
* 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
* @hotplug_slot: slot to free
@ -236,17 +142,6 @@ static int init_slots(struct controller *ctrl)
get_attention_status(hotplug_slot, &info->attention_status);
get_latch_status(hotplug_slot, &info->latch_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;
@ -261,13 +156,8 @@ error:
static void cleanup_slots(struct controller *ctrl)
{
struct slot *slot;
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);
list_for_each_entry(slot, &ctrl->slot_list, slot_list)
pci_hp_deregister(slot->hotplug_slot);
}
}
/*

View File

@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot)
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)
{
struct controller *ctrl = slot->ctrl;
@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_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_cur_bus_speed = hpc_get_cur_lnk_speed,

View File

@ -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 struct hotplug_slot_ops skel_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,

View File

@ -423,7 +423,6 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
}
struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,

View File

@ -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 struct hotplug_slot_ops sn_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.get_power_status = get_power_status,

View File

@ -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 struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
.owner = THIS_MODULE,
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = disable_slot,

View File

@ -110,7 +110,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
}
if (reset)
pci_execute_reset_function(virtfn);
__pci_reset_function(virtfn);
pci_device_add(virtfn, virtfn->bus);
mutex_unlock(&iov->dev->sriov->lock);
@ -164,7 +164,7 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
if (reset) {
device_release_driver(&virtfn->dev);
pci_execute_reset_function(virtfn);
__pci_reset_function(virtfn);
}
sprintf(buf, "virtfn%u", id);
@ -487,6 +487,8 @@ found:
iov->self = dev;
pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
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)
iov->dev = pci_dev_get(pdev);

View File

@ -75,22 +75,17 @@ void arch_teardown_msi_irqs(struct pci_dev *dev)
}
#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;
if (pos) {
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
}
}
BUG_ON(!pos);
static void msi_set_enable(struct pci_dev *dev, int enable)
{
__msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
}
static void msix_set_enable(struct pci_dev *dev, int enable)
@ -131,9 +126,6 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
* mask all MSI interrupts by clearing the MSI enable bit does not work
* reliably as devices without an INTx disable bit will then generate a
* 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)
{
@ -303,7 +295,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pos = entry->msi_attrib.pos;
pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0);
msi_set_enable(dev, pos, 0);
write_msi_msg(dev->irq, &entry->msg);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
@ -321,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
if (!dev->msix_enabled)
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 */
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) {
write_msi_msg(entry->irq, &entry->msg);
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_ENABLE;
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
}
@ -365,9 +357,9 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
u16 control;
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);
msi_set_enable(dev, pos, 0); /* Disable MSI during set up */
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
entry = alloc_msi_entry(dev);
@ -381,7 +373,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.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 */
if (entry->msi_attrib.maskbit)
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
@ -399,7 +391,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
/* Set MSI enabled bits */
pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 1);
msi_set_enable(dev, pos, 1);
dev->msi_enabled = 1;
dev->irq = entry->irq;
@ -427,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev,
u8 bir;
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);
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 */
pci_read_config_word(dev, msi_control_reg(pos), &control);
nr_entries = multi_msix_capable(control);
pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
@ -442,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev,
if (base == NULL)
return -ENOMEM;
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
entry = alloc_msi_entry(dev);
if (!entry)
@ -455,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.default_irq = dev->irq;
entry->msi_attrib.pos = pos;
entry->mask_base = base;
msix_mask_irq(entry, 1);
list_add_tail(&entry->list, &dev->msi_list);
}
@ -480,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev,
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;
list_for_each_entry(entry, &dev->msi_list, list) {
entries[i].vector = entry->irq;
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++;
}
/* Set MSI-X enabled bits */
/* Set MSI-X enabled bits and unmask the function */
pci_intx_for_msi(dev, 0);
msix_set_enable(dev, 1);
dev->msix_enabled = 1;
list_for_each_entry(entry, &dev->msi_list, list) {
int vector = entry->msi_attrib.entry_nr;
entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
}
control &= ~PCI_MSIX_FLAGS_MASKALL;
pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
return 0;
}
@ -596,17 +598,20 @@ void pci_msi_shutdown(struct pci_dev *dev)
struct msi_desc *desc;
u32 mask;
u16 ctrl;
unsigned pos;
if (!pci_msi_enable || !dev || !dev->msi_enabled)
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);
dev->msi_enabled = 0;
BUG_ON(list_empty(&dev->msi_list));
desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
mask = msi_capable_mask(ctrl);
msi_mask_irq(desc, mask, ~mask);
@ -648,10 +653,7 @@ static int msi_free_irqs(struct pci_dev* dev)
list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
if (entry->msi_attrib.is_msix) {
writel(1, entry->mask_base + entry->msi_attrib.entry_nr
* PCI_MSIX_ENTRY_SIZE
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
msix_mask_irq(entry, 1);
if (list_is_last(&entry->list, &dev->msi_list))
iounmap(entry->mask_base);
}
@ -691,8 +693,8 @@ int pci_msix_table_size(struct pci_dev *dev)
* indicates the successful configuration of MSI-X capability structure
* 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
* of irqs available. Driver should use the returned value to re-send
* its request.
* of irqs or MSI-X vectors available. Driver should use the returned value to
* re-send its request.
**/
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);
if (nvec > nr_entries)
return -EINVAL;
return nr_entries;
/* Check for any invalid entries */
for (i = 0; i < nvec; i++) {

View File

@ -16,21 +16,15 @@
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
#define msi_data_reg(base, is64bit) \
( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
#define msi_mask_bits_reg(base, is64bit) \
( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE
(base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32))
#define msi_mask_reg(base, is64bit) \
(base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
#define msix_table_offset_reg(base) (base + 0x04)
#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 multi_msix_capable msix_table_size
#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)
#define multi_msix_capable(control) msix_table_size((control))
#endif /* MSI_H */

View File

@ -485,6 +485,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
pmcsr |= state;
break;
case PCI_D3hot:
case PCI_D3cold:
case PCI_UNKNOWN: /* Boot-up */
if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
@ -1208,7 +1210,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
* Error code depending on the platform is returned if both the platform and
* the native mechanism fail to enable the generation of wake-up events
*/
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
{
int error = 0;
bool pme_done = false;
@ -1287,15 +1289,14 @@ pci_power_t pci_target_state(struct pci_dev *dev)
default:
target_state = state;
}
} else if (!dev->pm_cap) {
target_state = PCI_D0;
} else if (device_may_wakeup(&dev->dev)) {
/*
* Find the deepest state from which the device can generate
* wake-up events, make it the target state and enable device
* to generate PME#.
*/
if (!dev->pm_cap)
return PCI_POWER_ERROR;
if (dev->pme_support) {
while (target_state
&& !(dev->pme_support & (1 << target_state)))
@ -1532,7 +1533,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
if (!pin)
return -1;
while (dev->bus->parent) {
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
@ -1552,7 +1553,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (dev->bus->parent) {
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
@ -2058,111 +2059,177 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
#endif
static int __pcie_flr(struct pci_dev *dev, int probe)
static int pcie_flr(struct pci_dev *dev, int probe)
{
u16 status;
int i;
int pos;
u32 cap;
int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP);
u16 status;
if (!exppos)
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos)
return -ENOTTY;
pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap);
pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
if (!(cap & PCI_EXP_DEVCAP_FLR))
return -ENOTTY;
if (probe)
return 0;
pci_block_user_cfg_access(dev);
/* Wait for Transaction Pending bit clean */
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
goto transaction_done;
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
msleep(100);
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
goto transaction_done;
pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
goto clear;
}
dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
"sleeping for 1 second\n");
ssleep(1);
pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
if (status & PCI_EXP_DEVSTA_TRPND)
dev_info(&dev->dev, "Still busy after 1s; "
"proceeding with reset anyway\n");
dev_err(&dev->dev, "transaction is not cleared; "
"proceeding with reset anyway\n");
transaction_done:
pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL,
clear:
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_BCR_FLR);
mdelay(100);
msleep(100);
pci_unblock_user_cfg_access(dev);
return 0;
}
static int __pci_af_flr(struct pci_dev *dev, int probe)
static int pci_af_flr(struct pci_dev *dev, int probe)
{
int cappos = pci_find_capability(dev, PCI_CAP_ID_AF);
u8 status;
int i;
int pos;
u8 cap;
u8 status;
if (!cappos)
pos = pci_find_capability(dev, PCI_CAP_ID_AF);
if (!pos)
return -ENOTTY;
pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap);
pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap);
if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR))
return -ENOTTY;
if (probe)
return 0;
pci_block_user_cfg_access(dev);
/* Wait for Transaction Pending bit clean */
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
if (!(status & PCI_AF_STATUS_TP))
goto transaction_done;
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status);
if (!(status & PCI_AF_STATUS_TP))
goto clear;
}
dev_err(&dev->dev, "transaction is not cleared; "
"proceeding with reset anyway\n");
clear:
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
msleep(100);
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
if (!(status & PCI_AF_STATUS_TP))
goto transaction_done;
dev_info(&dev->dev, "Busy after 100ms while trying to"
" reset; sleeping for 1 second\n");
ssleep(1);
pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
if (status & PCI_AF_STATUS_TP)
dev_info(&dev->dev, "Still busy after 1s; "
"proceeding with reset anyway\n");
transaction_done:
pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
mdelay(100);
pci_unblock_user_cfg_access(dev);
return 0;
}
static int __pci_reset_function(struct pci_dev *pdev, int probe)
static int pci_pm_reset(struct pci_dev *dev, int probe)
{
int res;
u16 csr;
res = __pcie_flr(pdev, probe);
if (res != -ENOTTY)
return res;
if (!dev->pm_cap)
return -ENOTTY;
res = __pci_af_flr(pdev, probe);
if (res != -ENOTTY)
return res;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
if (csr & PCI_PM_CTRL_NO_SOFT_RESET)
return -ENOTTY;
return res;
if (probe)
return 0;
if (dev->current_state != PCI_D0)
return -EINVAL;
csr &= ~PCI_PM_CTRL_STATE_MASK;
csr |= PCI_D3hot;
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
msleep(pci_pm_d3_delay);
csr &= ~PCI_PM_CTRL_STATE_MASK;
csr |= PCI_D0;
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
msleep(pci_pm_d3_delay);
return 0;
}
static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
{
u16 ctrl;
struct pci_dev *pdev;
if (dev->subordinate)
return -ENOTTY;
list_for_each_entry(pdev, &dev->bus->devices, bus_list)
if (pdev != dev)
return -ENOTTY;
if (probe)
return 0;
pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl);
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
msleep(100);
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
msleep(100);
return 0;
}
static int pci_dev_reset(struct pci_dev *dev, int probe)
{
int rc;
might_sleep();
if (!probe) {
pci_block_user_cfg_access(dev);
/* block PM suspend, driver probe, etc. */
down(&dev->dev.sem);
}
rc = pcie_flr(dev, probe);
if (rc != -ENOTTY)
goto done;
rc = pci_af_flr(dev, probe);
if (rc != -ENOTTY)
goto done;
rc = pci_pm_reset(dev, probe);
if (rc != -ENOTTY)
goto done;
rc = pci_parent_bus_reset(dev, probe);
done:
if (!probe) {
up(&dev->dev.sem);
pci_unblock_user_cfg_access(dev);
}
return rc;
}
/**
* pci_execute_reset_function() - Reset a PCI device function
* @dev: Device function to reset
* __pci_reset_function - reset a PCI device function
* @dev: PCI device to reset
*
* Some devices allow an individual function to be reset without affecting
* other functions in the same device. The PCI device must be responsive
@ -2174,18 +2241,18 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe)
* device including MSI, bus mastering, BARs, decoding IO and memory spaces,
* etc.
*
* Returns 0 if the device function was successfully reset or -ENOTTY if the
* Returns 0 if the device function was successfully reset or negative if the
* device doesn't support resetting a single function.
*/
int pci_execute_reset_function(struct pci_dev *dev)
int __pci_reset_function(struct pci_dev *dev)
{
return __pci_reset_function(dev, 0);
return pci_dev_reset(dev, 0);
}
EXPORT_SYMBOL_GPL(pci_execute_reset_function);
EXPORT_SYMBOL_GPL(__pci_reset_function);
/**
* pci_reset_function() - quiesce and reset a PCI device function
* @dev: Device function to reset
* pci_reset_function - quiesce and reset a PCI device function
* @dev: PCI device to reset
*
* Some devices allow an individual function to be reset without affecting
* other functions in the same device. The PCI device must be responsive
@ -2193,32 +2260,33 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function);
*
* This function does not just reset the PCI portion of a device, but
* clears all the state associated with the device. This function differs
* from pci_execute_reset_function in that it saves and restores device state
* from __pci_reset_function in that it saves and restores device state
* over the reset.
*
* Returns 0 if the device function was successfully reset or -ENOTTY if the
* Returns 0 if the device function was successfully reset or negative if the
* device doesn't support resetting a single function.
*/
int pci_reset_function(struct pci_dev *dev)
{
int r = __pci_reset_function(dev, 1);
int rc;
if (r < 0)
return r;
rc = pci_dev_reset(dev, 1);
if (rc)
return rc;
if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0)
disable_irq(dev->irq);
pci_save_state(dev);
/*
* both INTx and MSI are disabled after the Interrupt Disable bit
* is set and the Bus Master bit is cleared.
*/
pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
r = pci_execute_reset_function(dev);
rc = pci_dev_reset(dev, 0);
pci_restore_state(dev);
if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0)
enable_irq(dev->irq);
return r;
return rc;
}
EXPORT_SYMBOL_GPL(pci_reset_function);
@ -2591,6 +2659,8 @@ static int __init pci_setup(char *str)
} else if (!strncmp(str, "resource_alignment=", 19)) {
pci_set_resource_alignment_param(str + 19,
strlen(str + 19));
} else if (!strncmp(str, "ecrc=", 5)) {
pcie_ecrc_get_policy(str + 5);
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);

View File

@ -10,3 +10,18 @@ config PCIEAER
This enables PCI Express Root Port Advanced Error Reporting
(AER) driver support. Error reporting messages sent to Root
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"

View File

@ -0,0 +1,18 @@
#
# PCI Express Root Port Device AER Debug Configuration
#
config PCIEAER_INJECT
tristate "PCIE AER error injector support"
depends on PCIEAER
default n
help
This enables PCI Express Root Port Advanced Error Reporting
(AER) software error injector.
Debuging PCIE AER code is quite difficult because it is hard
to trigger various real hardware errors. Software based
error injection can fake almost all kinds of errors with the
help of a user space helper tool aer-inject, which can be
gotten from:
http://www.kernel.org/pub/linux/utils/pci/aer-inject/

View File

@ -4,6 +4,9 @@
obj-$(CONFIG_PCIEAER) += aerdriver.o
obj-$(CONFIG_PCIE_ECRC) += ecrc.o
aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o
aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o

View File

@ -0,0 +1,473 @@
/*
* PCIE AER software error injection support.
*
* Debuging PCIE AER code is quite difficult because it is hard to
* trigger various real hardware errors. Software based error
* injection can fake almost all kinds of errors with the help of a
* user space helper tool aer-inject, which can be gotten from:
* http://www.kernel.org/pub/linux/utils/pci/aer-inject/
*
* Copyright 2009 Intel Corporation.
* Huang Ying <ying.huang@intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "aerdrv.h"
struct aer_error_inj
{
u8 bus;
u8 dev;
u8 fn;
u32 uncor_status;
u32 cor_status;
u32 header_log0;
u32 header_log1;
u32 header_log2;
u32 header_log3;
};
struct aer_error
{
struct list_head list;
unsigned int bus;
unsigned int devfn;
int pos_cap_err;
u32 uncor_status;
u32 cor_status;
u32 header_log0;
u32 header_log1;
u32 header_log2;
u32 header_log3;
u32 root_status;
u32 source_id;
};
struct pci_bus_ops
{
struct list_head list;
struct pci_bus *bus;
struct pci_ops *ops;
};
static LIST_HEAD(einjected);
static LIST_HEAD(pci_bus_ops_list);
/* Protect einjected and pci_bus_ops_list */
static DEFINE_SPINLOCK(inject_lock);
static void aer_error_init(struct aer_error *err, unsigned int bus,
unsigned int devfn, int pos_cap_err)
{
INIT_LIST_HEAD(&err->list);
err->bus = bus;
err->devfn = devfn;
err->pos_cap_err = pos_cap_err;
}
/* inject_lock must be held before calling */
static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn)
{
struct aer_error *err;
list_for_each_entry(err, &einjected, list) {
if (bus == err->bus && devfn == err->devfn)
return err;
}
return NULL;
}
/* inject_lock must be held before calling */
static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev)
{
return __find_aer_error(dev->bus->number, dev->devfn);
}
/* inject_lock must be held before calling */
static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus)
{
struct pci_bus_ops *bus_ops;
list_for_each_entry(bus_ops, &pci_bus_ops_list, list) {
if (bus_ops->bus == bus)
return bus_ops->ops;
}
return NULL;
}
static struct pci_bus_ops *pci_bus_ops_pop(void)
{
unsigned long flags;
struct pci_bus_ops *bus_ops = NULL;
spin_lock_irqsave(&inject_lock, flags);
if (list_empty(&pci_bus_ops_list))
bus_ops = NULL;
else {
struct list_head *lh = pci_bus_ops_list.next;
list_del(lh);
bus_ops = list_entry(lh, struct pci_bus_ops, list);
}
spin_unlock_irqrestore(&inject_lock, flags);
return bus_ops;
}
static u32 *find_pci_config_dword(struct aer_error *err, int where,
int *prw1cs)
{
int rw1cs = 0;
u32 *target = NULL;
if (err->pos_cap_err == -1)
return NULL;
switch (where - err->pos_cap_err) {
case PCI_ERR_UNCOR_STATUS:
target = &err->uncor_status;
rw1cs = 1;
break;
case PCI_ERR_COR_STATUS:
target = &err->cor_status;
rw1cs = 1;
break;
case PCI_ERR_HEADER_LOG:
target = &err->header_log0;
break;
case PCI_ERR_HEADER_LOG+4:
target = &err->header_log1;
break;
case PCI_ERR_HEADER_LOG+8:
target = &err->header_log2;
break;
case PCI_ERR_HEADER_LOG+12:
target = &err->header_log3;
break;
case PCI_ERR_ROOT_STATUS:
target = &err->root_status;
rw1cs = 1;
break;
case PCI_ERR_ROOT_COR_SRC:
target = &err->source_id;
break;
}
if (prw1cs)
*prw1cs = rw1cs;
return target;
}
static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val)
{
u32 *sim;
struct aer_error *err;
unsigned long flags;
struct pci_ops *ops;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
goto out;
err = __find_aer_error(bus->number, devfn);
if (!err)
goto out;
sim = find_pci_config_dword(err, where, NULL);
if (sim) {
*val = *sim;
spin_unlock_irqrestore(&inject_lock, flags);
return 0;
}
out:
ops = __find_pci_bus_ops(bus);
spin_unlock_irqrestore(&inject_lock, flags);
return ops->read(bus, devfn, where, size, val);
}
int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
u32 val)
{
u32 *sim;
struct aer_error *err;
unsigned long flags;
int rw1cs;
struct pci_ops *ops;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
goto out;
err = __find_aer_error(bus->number, devfn);
if (!err)
goto out;
sim = find_pci_config_dword(err, where, &rw1cs);
if (sim) {
if (rw1cs)
*sim ^= val;
else
*sim = val;
spin_unlock_irqrestore(&inject_lock, flags);
return 0;
}
out:
ops = __find_pci_bus_ops(bus);
spin_unlock_irqrestore(&inject_lock, flags);
return ops->write(bus, devfn, where, size, val);
}
static struct pci_ops pci_ops_aer = {
.read = pci_read_aer,
.write = pci_write_aer,
};
static void pci_bus_ops_init(struct pci_bus_ops *bus_ops,
struct pci_bus *bus,
struct pci_ops *ops)
{
INIT_LIST_HEAD(&bus_ops->list);
bus_ops->bus = bus;
bus_ops->ops = ops;
}
static int pci_bus_set_aer_ops(struct pci_bus *bus)
{
struct pci_ops *ops;
struct pci_bus_ops *bus_ops;
unsigned long flags;
bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL);
if (!bus_ops)
return -ENOMEM;
ops = pci_bus_set_ops(bus, &pci_ops_aer);
spin_lock_irqsave(&inject_lock, flags);
if (ops == &pci_ops_aer)
goto out;
pci_bus_ops_init(bus_ops, bus, ops);
list_add(&bus_ops->list, &pci_bus_ops_list);
bus_ops = NULL;
out:
spin_unlock_irqrestore(&inject_lock, flags);
if (bus_ops)
kfree(bus_ops);
return 0;
}
static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
{
while (1) {
if (!dev->is_pcie)
break;
if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
return dev;
if (!dev->bus->self)
break;
dev = dev->bus->self;
}
return NULL;
}
static int find_aer_device_iter(struct device *device, void *data)
{
struct pcie_device **result = data;
struct pcie_device *pcie_dev;
if (device->bus == &pcie_port_bus_type) {
pcie_dev = to_pcie_device(device);
if (pcie_dev->service & PCIE_PORT_SERVICE_AER) {
*result = pcie_dev;
return 1;
}
}
return 0;
}
static int find_aer_device(struct pci_dev *dev, struct pcie_device **result)
{
return device_for_each_child(&dev->dev, result, find_aer_device_iter);
}
static int aer_inject(struct aer_error_inj *einj)
{
struct aer_error *err, *rperr;
struct aer_error *err_alloc = NULL, *rperr_alloc = NULL;
struct pci_dev *dev, *rpdev;
struct pcie_device *edev;
unsigned long flags;
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
int pos_cap_err, rp_pos_cap_err;
u32 sever;
int ret = 0;
dev = pci_get_bus_and_slot(einj->bus, devfn);
if (!dev)
return -EINVAL;
rpdev = pcie_find_root_port(dev);
if (!rpdev) {
ret = -EINVAL;
goto out_put;
}
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos_cap_err) {
ret = -EIO;
goto out_put;
}
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) {
ret = -EIO;
goto out_put;
}
err_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL);
if (!err_alloc) {
ret = -ENOMEM;
goto out_put;
}
rperr_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL);
if (!rperr_alloc) {
ret = -ENOMEM;
goto out_put;
}
spin_lock_irqsave(&inject_lock, flags);
err = __find_aer_error_by_dev(dev);
if (!err) {
err = err_alloc;
err_alloc = NULL;
aer_error_init(err, einj->bus, devfn, pos_cap_err);
list_add(&err->list, &einjected);
}
err->uncor_status |= einj->uncor_status;
err->cor_status |= einj->cor_status;
err->header_log0 = einj->header_log0;
err->header_log1 = einj->header_log1;
err->header_log2 = einj->header_log2;
err->header_log3 = einj->header_log3;
rperr = __find_aer_error_by_dev(rpdev);
if (!rperr) {
rperr = rperr_alloc;
rperr_alloc = NULL;
aer_error_init(rperr, rpdev->bus->number, rpdev->devfn,
rp_pos_cap_err);
list_add(&rperr->list, &einjected);
}
if (einj->cor_status) {
if (rperr->root_status & PCI_ERR_ROOT_COR_RCV)
rperr->root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
else
rperr->root_status |= PCI_ERR_ROOT_COR_RCV;
rperr->source_id &= 0xffff0000;
rperr->source_id |= (einj->bus << 8) | devfn;
}
if (einj->uncor_status) {
if (rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV)
rperr->root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
if (sever & einj->uncor_status) {
rperr->root_status |= PCI_ERR_ROOT_FATAL_RCV;
if (!(rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV))
rperr->root_status |= PCI_ERR_ROOT_FIRST_FATAL;
} else
rperr->root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
rperr->root_status |= PCI_ERR_ROOT_UNCOR_RCV;
rperr->source_id &= 0x0000ffff;
rperr->source_id |= ((einj->bus << 8) | devfn) << 16;
}
spin_unlock_irqrestore(&inject_lock, flags);
ret = pci_bus_set_aer_ops(dev->bus);
if (ret)
goto out_put;
ret = pci_bus_set_aer_ops(rpdev->bus);
if (ret)
goto out_put;
if (find_aer_device(rpdev, &edev))
aer_irq(-1, edev);
else
ret = -EINVAL;
out_put:
if (err_alloc)
kfree(err_alloc);
if (rperr_alloc)
kfree(rperr_alloc);
pci_dev_put(dev);
return ret;
}
static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf,
size_t usize, loff_t *off)
{
struct aer_error_inj einj;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (usize != sizeof(struct aer_error_inj))
return -EINVAL;
if (copy_from_user(&einj, ubuf, usize))
return -EFAULT;
ret = aer_inject(&einj);
return ret ? ret : usize;
}
static const struct file_operations aer_inject_fops = {
.write = aer_inject_write,
.owner = THIS_MODULE,
};
static struct miscdevice aer_inject_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "aer_inject",
.fops = &aer_inject_fops,
};
static int __init aer_inject_init(void)
{
return misc_register(&aer_inject_device);
}
static void __exit aer_inject_exit(void)
{
struct aer_error *err, *err_next;
unsigned long flags;
struct pci_bus_ops *bus_ops;
misc_deregister(&aer_inject_device);
while ((bus_ops = pci_bus_ops_pop())) {
pci_bus_set_ops(bus_ops->bus, bus_ops->ops);
kfree(bus_ops);
}
spin_lock_irqsave(&inject_lock, flags);
list_for_each_entry_safe(err, err_next,
&pci_bus_ops_list, list) {
list_del(&err->list);
kfree(err);
}
spin_unlock_irqrestore(&inject_lock, flags);
}
module_init(aer_inject_init);
module_exit(aer_inject_exit);
MODULE_DESCRIPTION("PCIE AER software error injector");
MODULE_LICENSE("GPL");

View File

@ -77,7 +77,7 @@ void pci_no_aer(void)
*
* 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;
struct pcie_device *pdev = (struct pcie_device *)context;
@ -126,6 +126,7 @@ static irqreturn_t aer_irq(int irq, void *context)
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(aer_irq);
/**
* aer_alloc_rpc - allocate Root Port data structure

View File

@ -11,6 +11,7 @@
#include <linux/workqueue.h>
#include <linux/pcieport_if.h>
#include <linux/aer.h>
#include <linux/interrupt.h>
#define AER_NONFATAL 0
#define AER_FATAL 1
@ -56,7 +57,11 @@ struct header_log_regs {
unsigned int dw3;
};
#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */
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 flags;
unsigned int status; /* COR/UNCOR Error Status */
@ -120,6 +125,7 @@ extern void aer_delete_rootport(struct aer_rpc *rpc);
extern int aer_init(struct pcie_device *dev);
extern void aer_isr(struct work_struct *work);
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
extern int aer_osc_setup(struct pcie_device *pciedev);

View File

@ -26,7 +26,9 @@
#include "aerdrv.h"
static int forceload;
static int nosourceid;
module_param(forceload, bool, 0);
module_param(nosourceid, bool, 0);
int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
@ -109,19 +111,23 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
#endif /* 0 */
static void set_device_error_reporting(struct pci_dev *dev, void *data)
static int set_device_error_reporting(struct pci_dev *dev, void *data)
{
bool enable = *((bool *)data);
if (dev->pcie_type != PCIE_RC_PORT &&
dev->pcie_type != PCIE_SW_UPSTREAM_PORT &&
dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT)
return;
if (dev->pcie_type == PCIE_RC_PORT ||
dev->pcie_type == PCIE_SW_UPSTREAM_PORT ||
dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) {
if (enable)
pci_enable_pcie_error_reporting(dev);
else
pci_disable_pcie_error_reporting(dev);
}
if (enable)
pci_enable_pcie_error_reporting(dev);
else
pci_disable_pcie_error_reporting(dev);
pcie_set_ecrc_checking(dev);
return 0;
}
/**
@ -139,73 +145,148 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
}
static int find_device_iter(struct device *device, void *data)
static inline int compare_device_id(struct pci_dev *dev,
struct aer_err_info *e_info)
{
struct pci_dev *dev;
u16 id = *(unsigned long *)data;
u8 secondary, subordinate, d_bus = id >> 8;
if (device->bus == &pci_bus_type) {
dev = to_pci_dev(device);
if (id == ((dev->bus->number << 8) | dev->devfn)) {
/*
* Device ID match
*/
*(unsigned long*)data = (unsigned long)device;
return 1;
}
if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) {
/*
* If device is P2P, check if it is an upstream?
* Device ID match
*/
if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
&secondary);
pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
&subordinate);
if (d_bus >= secondary && d_bus <= subordinate) {
*(unsigned long*)data = (unsigned long)device;
return 1;
}
}
return 1;
}
return 0;
}
static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
{
if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
e_info->dev[e_info->error_dev_num] = dev;
e_info->error_dev_num++;
return 1;
} else
return 0;
}
#define PCI_BUS(x) (((x) >> 8) & 0xff)
static int find_device_iter(struct pci_dev *dev, void *data)
{
int pos;
u32 status;
u32 mask;
u16 reg16;
int result;
struct aer_err_info *e_info = (struct aer_err_info *)data;
/*
* When bus id is equal to 0, it might be a bad id
* reported by root port.
*/
if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
result = compare_device_id(dev, e_info);
if (result)
add_error_device(e_info, dev);
/*
* If there is no multiple error, we stop
* or continue based on the id comparing.
*/
if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG))
return result;
/*
* If there are multiple errors and id does match,
* We need continue to search other devices under
* the root port. Return 0 means that.
*/
if (result)
return 0;
}
/*
* When either
* 1) nosourceid==y;
* 2) bus id is equal to 0. Some ports might lose the bus
* id of error source id;
* 3) There are multiple errors and prior id comparing fails;
* We check AER status registers to find the initial reporter.
*/
if (atomic_read(&dev->enable_cnt) == 0)
return 0;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos)
return 0;
/* Check if AER is enabled */
pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
if (!(reg16 & (
PCI_EXP_DEVCTL_CERE |
PCI_EXP_DEVCTL_NFERE |
PCI_EXP_DEVCTL_FERE |
PCI_EXP_DEVCTL_URRE)))
return 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return 0;
status = 0;
mask = 0;
if (e_info->severity == AER_CORRECTABLE) {
pci_read_config_dword(dev,
pos + PCI_ERR_COR_STATUS,
&status);
pci_read_config_dword(dev,
pos + PCI_ERR_COR_MASK,
&mask);
if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) {
add_error_device(e_info, dev);
goto added;
}
} else {
pci_read_config_dword(dev,
pos + PCI_ERR_UNCOR_STATUS,
&status);
pci_read_config_dword(dev,
pos + PCI_ERR_UNCOR_MASK,
&mask);
if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) {
add_error_device(e_info, dev);
goto added;
}
}
return 0;
added:
if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG)
return 0;
else
return 1;
}
/**
* find_source_device - search through device hierarchy for source device
* @parent: pointer to Root Port pci_dev data structure
* @id: device ID of agent who sends an error message to this Root Port
* @err_info: including detailed error information such like id
*
* Invoked when error is detected at the Root Port.
*/
static struct device* find_source_device(struct pci_dev *parent, u16 id)
static void find_source_device(struct pci_dev *parent,
struct aer_err_info *e_info)
{
struct pci_dev *dev = parent;
struct device *device;
unsigned long device_addr;
int status;
int result;
/* Is Root Port an agent that sends error message? */
if (id == ((dev->bus->number << 8) | dev->devfn))
return &dev->dev;
result = find_device_iter(dev, e_info);
if (result)
return;
do {
device_addr = id;
if ((status = device_for_each_child(&dev->dev,
&device_addr, find_device_iter))) {
device = (struct device*)device_addr;
dev = to_pci_dev(device);
if (id == ((dev->bus->number << 8) | dev->devfn))
return device;
}
}while (status);
return NULL;
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
}
static void report_error_detected(struct pci_dev *dev, void *data)
static int report_error_detected(struct pci_dev *dev, void *data)
{
pci_ers_result_t vote;
struct pci_error_handlers *err_handler;
@ -230,16 +311,16 @@ static void report_error_detected(struct pci_dev *dev, void *data)
dev->driver ?
"no AER-aware driver" : "no driver");
}
return;
return 0;
}
err_handler = dev->driver->err_handler;
vote = err_handler->error_detected(dev, result_data->state);
result_data->result = merge_result(result_data->result, vote);
return;
return 0;
}
static void report_mmio_enabled(struct pci_dev *dev, void *data)
static int report_mmio_enabled(struct pci_dev *dev, void *data)
{
pci_ers_result_t vote;
struct pci_error_handlers *err_handler;
@ -249,15 +330,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data)
if (!dev->driver ||
!dev->driver->err_handler ||
!dev->driver->err_handler->mmio_enabled)
return;
return 0;
err_handler = dev->driver->err_handler;
vote = err_handler->mmio_enabled(dev);
result_data->result = merge_result(result_data->result, vote);
return;
return 0;
}
static void report_slot_reset(struct pci_dev *dev, void *data)
static int report_slot_reset(struct pci_dev *dev, void *data)
{
pci_ers_result_t vote;
struct pci_error_handlers *err_handler;
@ -267,15 +348,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data)
if (!dev->driver ||
!dev->driver->err_handler ||
!dev->driver->err_handler->slot_reset)
return;
return 0;
err_handler = dev->driver->err_handler;
vote = err_handler->slot_reset(dev);
result_data->result = merge_result(result_data->result, vote);
return;
return 0;
}
static void report_resume(struct pci_dev *dev, void *data)
static int report_resume(struct pci_dev *dev, void *data)
{
struct pci_error_handlers *err_handler;
@ -284,11 +365,11 @@ static void report_resume(struct pci_dev *dev, void *data)
if (!dev->driver ||
!dev->driver->err_handler ||
!dev->driver->err_handler->resume)
return;
return 0;
err_handler = dev->driver->err_handler;
err_handler->resume(dev);
return;
return 0;
}
/**
@ -305,7 +386,7 @@ static void report_resume(struct pci_dev *dev, void *data)
static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
enum pci_channel_state state,
char *error_mesg,
void (*cb)(struct pci_dev *, void *))
int (*cb)(struct pci_dev *, void *))
{
struct aer_broadcast_data result_data;
@ -497,12 +578,12 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
*/
static void handle_error_source(struct pcie_device * aerdev,
struct pci_dev *dev,
struct aer_err_info info)
struct aer_err_info *info)
{
pci_ers_result_t status = 0;
int pos;
if (info.severity == AER_CORRECTABLE) {
if (info->severity == AER_CORRECTABLE) {
/*
* Correctable error does not need software intevention.
* No need to go through error recovery process.
@ -510,9 +591,9 @@ static void handle_error_source(struct pcie_device * aerdev,
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (pos)
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
info.status);
info->status);
} else {
status = do_recovery(aerdev, dev, info.severity);
status = do_recovery(aerdev, dev, info->severity);
if (status == PCI_ERS_RESULT_RECOVERED) {
dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
"successfully recovered\n");
@ -661,6 +742,28 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
return AER_SUCCESS;
}
static inline void aer_process_err_devices(struct pcie_device *p_device,
struct aer_err_info *e_info)
{
int i;
if (!e_info->dev[0]) {
dev_printk(KERN_DEBUG, &p_device->port->dev,
"can't find device of ID%04x\n",
e_info->id);
}
for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {
if (get_device_error_info(e_info->dev[i], e_info) ==
AER_SUCCESS) {
aer_print_error(e_info->dev[i], e_info);
handle_error_source(p_device,
e_info->dev[i],
e_info);
}
}
}
/**
* aer_isr_one_error - consume an error detected by root port
* @p_device: pointer to error root port service device
@ -669,10 +772,16 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
static void aer_isr_one_error(struct pcie_device *p_device,
struct aer_err_source *e_src)
{
struct device *s_device;
struct aer_err_info e_info = {0, 0, 0,};
struct aer_err_info *e_info;
int i;
u16 id;
/* struct aer_err_info might be big, so we allocate it with slab */
e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL);
if (e_info == NULL) {
dev_printk(KERN_DEBUG, &p_device->port->dev,
"Can't allocate mem when processing AER errors\n");
return;
}
/*
* There is a possibility that both correctable error and
@ -684,31 +793,26 @@ static void aer_isr_one_error(struct pcie_device *p_device,
if (!(e_src->status & i))
continue;
memset(e_info, 0, sizeof(struct aer_err_info));
/* Init comprehensive error information */
if (i & PCI_ERR_ROOT_COR_RCV) {
id = ERR_COR_ID(e_src->id);
e_info.severity = AER_CORRECTABLE;
e_info->id = ERR_COR_ID(e_src->id);
e_info->severity = AER_CORRECTABLE;
} else {
id = ERR_UNCOR_ID(e_src->id);
e_info.severity = ((e_src->status >> 6) & 1);
e_info->id = ERR_UNCOR_ID(e_src->id);
e_info->severity = ((e_src->status >> 6) & 1);
}
if (e_src->status &
(PCI_ERR_ROOT_MULTI_COR_RCV |
PCI_ERR_ROOT_MULTI_UNCOR_RCV))
e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
if (!(s_device = find_source_device(p_device->port, id))) {
printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
__func__, id);
continue;
}
if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
AER_SUCCESS) {
aer_print_error(to_pci_dev(s_device), &e_info);
handle_error_source(p_device,
to_pci_dev(s_device),
e_info);
}
e_info->flags |= AER_MULTI_ERROR_VALID_FLAG;
find_source_device(p_device->port, e_info);
aer_process_err_devices(p_device, e_info);
}
kfree(e_info);
}
/**

131
drivers/pci/pcie/aer/ecrc.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Enables/disables PCIe ECRC checking.
*
* (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
* Andrew Patterson <andrew.patterson@hp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/errno.h>
#include "../../pci.h"
#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */
#define ECRC_POLICY_OFF 1 /* ECRC off for performance */
#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */
static int ecrc_policy = ECRC_POLICY_DEFAULT;
static const char *ecrc_policy_str[] = {
[ECRC_POLICY_DEFAULT] = "bios",
[ECRC_POLICY_OFF] = "off",
[ECRC_POLICY_ON] = "on"
};
/**
* enable_ercr_checking - enable PCIe ECRC checking for a device
* @dev: the PCI device
*
* Returns 0 on success, or negative on failure.
*/
static int enable_ecrc_checking(struct pci_dev *dev)
{
int pos;
u32 reg32;
if (!dev->is_pcie)
return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return -ENODEV;
pci_read_config_dword(dev, pos + PCI_ERR_CAP, &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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
if (type == pci_bar_io) {
l &= PCI_BASE_ADDRESS_IO_MASK;
mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT;
} else {
l &= PCI_BASE_ADDRESS_MEM_MASK;
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
@ -237,6 +237,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
dev_printk(KERN_DEBUG, &dev->dev,
"reg %x 64bit mmio: %pR\n", pos, res);
}
res->flags |= IORESOURCE_MEM_64;
} else {
sz = pci_size(l, sz, mask);
@ -287,7 +289,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
struct resource *res;
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;
if (dev->transparent) {
@ -362,7 +364,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
}
}
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->end = limit + 0xfffff;
dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n",

View File

@ -1133,6 +1133,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
case 0x1821: /* M5N notebook */
case 0x1897: /* A6L notebook */
asus_hides_smbus = 1;
}
else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
@ -1163,6 +1164,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
switch (dev->subsystem_device) {
case 0x12bc: /* HP D330L */
case 0x12bd: /* HP D530 */
case 0x006a: /* HP Compaq nx9500 */
asus_hides_smbus = 1;
}
else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
@ -2016,6 +2018,28 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
PCI_DEVICE_ID_NX2_5709S,
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
/* 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

View File

@ -32,8 +32,6 @@ static void pci_stop_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
* list accesses from this device */
down_write(&pci_bus_sem);

View File

@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
if (pdev->is_pcie)
return NULL;
while (1) {
if (!pdev->bus->parent)
if (pci_is_root_bus(pdev->bus))
break;
pdev = pdev->bus->self;
/* a p2p bridge */
@ -114,36 +114,6 @@ pci_find_next_bus(const struct pci_bus *from)
}
#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
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids

View File

@ -58,7 +58,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
res = list->res;
idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) {
/* FIXME: get rid of this */
res->start = 0;
res->end = 0;
res->flags = 0;
@ -143,6 +142,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
u32 l, bu, lu, io_upper16;
int pref_mem64;
if (pci_is_enabled(bridge))
return;
@ -198,16 +198,22 @@ static void pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */
pref_mem64 = 0;
bu = lu = 0;
pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
int width = 8;
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n",
(unsigned long long)region.start,
(unsigned long long)region.end);
if (bus->resource[2]->flags & IORESOURCE_MEM_64) {
pref_mem64 = 1;
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
width = 16;
}
dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n",
width, (unsigned long long)region.start,
width, (unsigned long long)region.end);
}
else {
l = 0x0000fff0;
@ -215,9 +221,11 @@ static void pci_setup_bridge(struct pci_bus *bus)
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
/* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
if (pref_mem64) {
/* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
}
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
@ -255,8 +263,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
}
if (pmem)
if (pmem) {
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
b_res[2].flags |= IORESOURCE_MEM_64;
}
/* double check if bridge does support 64 bit pref */
if (b_res[2].flags & IORESOURCE_MEM_64) {
u32 mem_base_hi, tmp;
pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32,
&mem_base_hi);
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
0xffffffff);
pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
if (!tmp)
b_res[2].flags &= ~IORESOURCE_MEM_64;
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
mem_base_hi);
}
}
/* Helper function for sizing routines: find first available
@ -336,6 +361,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
unsigned int mem64_mask = 0;
if (!b_res)
return 0;
@ -344,9 +370,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
max_order = 0;
size = 0;
mem64_mask = b_res->flags & IORESOURCE_MEM_64;
b_res->flags &= ~IORESOURCE_MEM_64;
list_for_each_entry(dev, &bus->devices, bus_list) {
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
resource_size_t r_size;
@ -372,6 +401,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
aligns[order] += align;
if (order > max_order)
max_order = order;
mem64_mask &= r->flags & IORESOURCE_MEM_64;
}
}
@ -396,6 +426,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
b_res->start = min_align;
b_res->end = size + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
b_res->flags |= mem64_mask;
return 1;
}

View File

@ -135,23 +135,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
}
#endif /* CONFIG_PCI_QUIRKS */
int pci_assign_resource(struct pci_dev *dev, int resno)
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
int resno)
{
struct pci_bus *bus = dev->bus;
struct resource *res = dev->resource + resno;
resource_size_t size, min, align;
int ret;
size = resource_size(res);
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
align = resource_alignment(res);
if (!align) {
dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
"alignment) %pR flags %#lx\n",
resno, res, res->flags);
return -EINVAL;
}
/* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min,
@ -169,10 +162,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
pcibios_align_resource, dev);
}
if (ret) {
dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
} else {
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
@ -181,6 +171,39 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
return ret;
}
int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct resource *res = dev->resource + resno;
resource_size_t align;
struct pci_bus *bus;
int ret;
align = resource_alignment(res);
if (!align) {
dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
"alignment) %pR flags %#lx\n",
resno, res, res->flags);
return -EINVAL;
}
bus = dev->bus;
while ((ret = __pci_assign_resource(bus, dev, resno))) {
if (bus->parent && bus->self->transparent)
bus = bus->parent;
else
bus = NULL;
if (bus)
continue;
break;
}
if (ret)
dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
return ret;
}
#if 0
int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
{

View File

@ -307,6 +307,45 @@ void pci_destroy_slot(struct pci_slot *slot)
}
EXPORT_SYMBOL_GPL(pci_destroy_slot);
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
#include <linux/pci_hotplug.h>
/**
* pci_hp_create_link - create symbolic link to the hotplug driver module.
* @slot: struct pci_slot
*
* Helper function for pci_hotplug_core.c to create symbolic link to
* the hotplug driver module.
*/
void pci_hp_create_module_link(struct pci_slot *pci_slot)
{
struct hotplug_slot *slot = pci_slot->hotplug;
struct kobject *kobj = NULL;
int no_warn;
if (!slot || !slot->ops)
return;
kobj = kset_find_obj(module_kset, slot->ops->mod_name);
if (!kobj)
return;
no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module");
kobject_put(kobj);
}
EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
/**
* pci_hp_remove_link - remove symbolic link to the hotplug driver module.
* @slot: struct pci_slot
*
* Helper function for pci_hotplug_core.c to remove symbolic link to
* the hotplug driver module.
*/
void pci_hp_remove_module_link(struct pci_slot *pci_slot)
{
sysfs_remove_link(&pci_slot->kobj, "module");
}
EXPORT_SYMBOL_GPL(pci_hp_remove_module_link);
#endif
static int pci_slot_init(void)
{
struct kset *pci_bus_kset;

View File

@ -49,6 +49,8 @@ struct resource_list {
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates 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_DISABLED 0x10000000
#define IORESOURCE_UNSET 0x20000000

View File

@ -15,7 +15,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
{
struct pci_bus *pbus = pdev->bus;
/* Find a PCI root bus */
while (pbus->parent)
while (!pci_is_root_bus(pbus))
pbus = pbus->parent;
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
pbus->number);
@ -23,7 +23,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
{
if (pbus->parent)
if (!pci_is_root_bus(pbus))
return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
pbus->number);

View File

@ -607,8 +607,6 @@ extern void pci_sort_breadthfirst(void);
struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
unsigned int device,
struct pci_dev *from);
struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
unsigned int devfn);
#endif /* CONFIG_PCI_LEGACY */
enum pci_lost_interrupt_reason {
@ -647,6 +645,7 @@ int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
int where, u16 val);
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
int where, u32 val);
struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops);
static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
{
@ -711,8 +710,8 @@ int pcix_get_mmrbc(struct pci_dev *dev);
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
int pcie_get_readrq(struct pci_dev *dev);
int pcie_set_readrq(struct pci_dev *dev, int rq);
int __pci_reset_function(struct pci_dev *dev);
int pci_reset_function(struct pci_dev *dev);
int pci_execute_reset_function(struct pci_dev *dev);
void pci_update_resource(struct pci_dev *dev, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
@ -732,7 +731,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
void pci_pme_active(struct pci_dev *dev, bool enable);
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable);
int pci_wake_from_d3(struct pci_dev *dev, bool enable);
pci_power_t pci_target_state(struct pci_dev *dev);
int pci_prepare_to_sleep(struct pci_dev *dev);
@ -798,7 +797,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
int pass);
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
void *userdata);
int pci_cfg_space_size_ext(struct pci_dev *dev);
int pci_cfg_space_size(struct pci_dev *dev);
@ -888,6 +887,17 @@ static inline int pcie_aspm_enabled(void)
extern int pcie_aspm_enabled(void);
#endif
#ifndef CONFIG_PCIE_ECRC
static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
{
return;
}
static inline void pcie_ecrc_get_policy(char *str) {};
#else
extern void pcie_set_ecrc_checking(struct pci_dev *dev);
extern void pcie_ecrc_get_policy(char *str);
#endif
#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1)
#ifdef CONFIG_HT_IRQ
@ -944,12 +954,6 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor,
return NULL;
}
static inline struct pci_dev *pci_find_slot(unsigned int bus,
unsigned int devfn)
{
return NULL;
}
static inline struct pci_dev *pci_get_device(unsigned int vendor,
unsigned int device,
struct pci_dev *from)
@ -1105,6 +1109,10 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
#include <asm/pci.h>
#ifndef PCIBIOS_MAX_MEM_32
#define PCIBIOS_MAX_MEM_32 (-1)
#endif
/* these helpers provide future and backwards compatibility
* for accessing popular PCI BAR info */
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
@ -1261,5 +1269,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
}
#endif
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
extern void pci_hp_create_module_link(struct pci_slot *pci_slot);
extern void pci_hp_remove_module_link(struct pci_slot *pci_slot);
#endif
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */

View File

@ -66,17 +66,10 @@ enum pcie_link_speed {
PCIE_LNK_SPEED_UNKNOWN = 0xFF,
};
struct hotplug_slot;
struct hotplug_slot_attribute {
struct attribute attr;
ssize_t (*show)(struct hotplug_slot *, char *);
ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
};
#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);
/**
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
* @owner: The module owner of this structure
* @mod_name: The module name (KBUILD_MODNAME) of this structure
* @enable_slot: Called when the user wants to enable a specific pci slot
* @disable_slot: Called when the user wants to disable a specific pci slot
* @set_attention_status: Called to set the specific slot's attention LED to
@ -109,6 +102,7 @@ struct hotplug_slot_attribute {
*/
struct hotplug_slot_ops {
struct module *owner;
const char *mod_name;
int (*enable_slot) (struct hotplug_slot *slot);
int (*disable_slot) (struct hotplug_slot *slot);
int (*set_attention_status) (struct hotplug_slot *slot, u8 value);
@ -167,12 +161,21 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
return pci_slot_name(slot->pci_slot);
}
extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr,
const char *name);
extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus,
int nr, const char *name,
struct module *owner, const char *mod_name);
extern int pci_hp_deregister(struct hotplug_slot *slot);
extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
struct hotplug_slot_info *info);
static inline int pci_hp_register(struct hotplug_slot *slot,
struct pci_bus *pbus,
int devnr, const char *name)
{
return __pci_hp_register(slot, pbus, devnr, name,
THIS_MODULE, KBUILD_MODNAME);
}
/* PCI Setting Record (Type 0) */
struct hpp_type0 {
u32 revision;

View File

@ -295,8 +295,9 @@
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
#define PCI_MSIX_FLAGS 2
@ -304,7 +305,6 @@
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
/* CompactPCI Hotswap Register */