From e55dea58c5609aece6156a6cd2306b820a7794ef Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 4 Apr 2006 09:26:46 -0400 Subject: [PATCH] PCI Hotplug: Tollhouse HP: SGI hotplug driver changes SGI hotplug driver changes required to support Tollhouse system PCI hotplug, and implements the PRF_HOTPLUG_SUPPORT feature bit. Signed-off-by: Prarit Bhargava Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/sgi_hotplug.c | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 8cb9abde736b..cfee9db52c49 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -18,11 +18,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -102,8 +104,7 @@ static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) { struct pcibus_info *pcibus_info; - int bricktype; - int bus_num; + u16 busnum, segment, ioboard_type; pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); @@ -111,12 +112,14 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) if (!(pcibus_info->pbi_valid_devices & (1 << device))) return -EPERM; - bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); - bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf; + ioboard_type = sn_ioboard_to_pci_bus(pci_bus); + busnum = pcibus_info->pbi_buscommon.bs_persist_busnum; + segment = pci_domain_nr(pci_bus) & 0xf; /* Do not allow hotplug operations on base I/O cards */ - if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) && - (bus_num == 1 && device != 1)) + if ((ioboard_type == L1_BRICKTYPE_IX || + ioboard_type == L1_BRICKTYPE_IA) && + (segment == 1 && busnum == 0 && device != 1)) return -EPERM; return 1; @@ -125,23 +128,23 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) static int sn_pci_bus_valid(struct pci_bus *pci_bus) { struct pcibus_info *pcibus_info; - int asic_type; - int bricktype; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); + u32 asic_type; + u16 ioboard_type; /* Don't register slots hanging off the TIOCA bus */ + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); asic_type = pcibus_info->pbi_buscommon.bs_asic_type; if (asic_type == PCIIO_ASIC_TYPE_TIOCA) return -EPERM; /* Only register slots in I/O Bricks that support hotplug */ - bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); - switch (bricktype) { + ioboard_type = sn_ioboard_to_pci_bus(pci_bus); + switch (ioboard_type) { case L1_BRICKTYPE_IX: case L1_BRICKTYPE_PX: case L1_BRICKTYPE_IA: case L1_BRICKTYPE_PA: + case L1_BOARDTYPE_PCIX3SLOT: return 1; break; default: @@ -175,14 +178,11 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, slot->pci_bus = pci_bus; sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", pci_domain_nr(pci_bus), - ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, + ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), device + 1); - sprintf(slot->physical_path, "module_%c%c%c%c%.2d", - '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), - '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), - '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), - MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), - MODULE_GET_BPOS(pcibus_info->pbi_moduleid)); + + sn_generate_path(pci_bus, slot->physical_path); + slot->hotplug_slot = bss_hotplug_slot; list_add(&slot->hp_list, &sn_hp_list); @@ -553,8 +553,8 @@ static int sn_pci_hotplug_init(void) int rc; int registered = 0; - if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { - printk(KERN_ERR "%s: PROM version must be greater than 4.30\n", + if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) { + printk(KERN_ERR "%s: PROM version does not support hotplug.\n", __FUNCTION__); return -EPERM; } -- cgit v1.2.2 From 92c9be95549632da09088320f202fa5c05b21ddf Mon Sep 17 00:00:00 2001 From: MUNEDA Takahiro Date: Wed, 22 Mar 2006 14:49:09 +0900 Subject: [PATCH] acpiphp: configure _PRT - V3 Current acpiphp does not free acpi_device structs when the PCI devices are removed. When the PCI device is added, acpi_bus_add() fails because acpi_device struct has already exists. So, _PRT method does not evaluate. This patch fixes this issue. Signed-off-by: MUNEDA Takahiro Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 71 ++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 38 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 053ee843863c..fadd264b64c3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -797,36 +797,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) } - -/** - * get_func - get a pointer to acpiphp_func given a slot, device - * @slot: slot to search - * @dev: pci_dev struct to match. - * - * This function will increase the reference count of pci_dev, - * so callers should call pci_dev_put when complete. - * - */ -static struct acpiphp_func * -get_func(struct acpiphp_slot *slot, struct pci_dev *dev) -{ - struct acpiphp_func *func = NULL; - struct pci_bus *bus = slot->bridge->pci_bus; - struct pci_dev *pdev; - - list_for_each_entry(func, &slot->funcs, sibling) { - pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, - func->function)); - if (pdev) { - if (pdev == dev) - break; - pci_dev_put(pdev); - } - } - return func; -} - - /** * acpiphp_bus_add - add a new bus to acpi subsystem * @func: acpiphp_func of the bridge @@ -872,6 +842,28 @@ acpiphp_bus_add_out: } +/** + * acpiphp_bus_trim - trim a bus from acpi subsystem + * @handle: handle to acpi namespace + * + */ +int acpiphp_bus_trim(acpi_handle handle) +{ + struct acpi_device *device; + int retval; + + retval = acpi_bus_get_device(handle, &device); + if (retval) { + dbg("acpi_device not found\n"); + return retval; + } + + retval = acpi_bus_trim(device, 1); + if (retval) + err("cannot remove from acpi list\n"); + + return retval; +} /** * enable_device - enable, configure a slot @@ -918,19 +910,17 @@ static int enable_device(struct acpiphp_slot *slot) if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { max = pci_scan_bridge(bus, dev, max, pass); - if (pass && dev->subordinate) { + if (pass && dev->subordinate) pci_bus_size_bridges(dev->subordinate); - func = get_func(slot, dev); - if (func) { - acpiphp_bus_add(func); - /* side effect of get_func */ - pci_dev_put(dev); - } - } } } } + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + acpiphp_bus_add(func); + } + pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); pci_enable_bridges(bus); @@ -967,6 +957,11 @@ static int disable_device(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); + + acpiphp_bus_trim(func->handle); + /* try to remove anyway. + * acpiphp_bus_add might have been failed */ + if (!func->pci_dev) continue; -- cgit v1.2.2 From 551bcb75b3d9f23348a524210ccfff26d865e425 Mon Sep 17 00:00:00 2001 From: MUNEDA Takahiro Date: Wed, 22 Mar 2006 14:49:20 +0900 Subject: [PATCH] acpiphp: hotplug slot hotplug o hotplug slots add When the hot-added PCI device is p2p bridge, acpiphp calls find_p2p_bridge() to add hotplug slots. o hotplug slots remove When the hot-removing PCI device is p2p bridge, acpiphp calls cleanup_p2p_bridge() to remove hotplug slots. o notify handler exchange When the p2p bridge is added, acpiphp changes the notify hanlder. If no bridge device is inserted into the hotpluggable PCI slot, acpiphp installs the notify handler for function. After the p2p bridge hot-add, acpiphp has to install the notify handler for bridge. Because, the role of the handlers are not same. The hot-remove case is ditto. Signed-off-by: MUNEDA Takahiro Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp.h | 5 ++ drivers/pci/hotplug/acpiphp_glue.c | 126 ++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 467ac70a46ff..17a93f890dba 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -75,6 +75,10 @@ struct acpiphp_bridge { struct list_head list; acpi_handle handle; struct acpiphp_slot *slots; + + /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ + struct acpiphp_func *func; + int type; int nr_slots; @@ -122,6 +126,7 @@ struct acpiphp_slot { */ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ + struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ struct list_head sibling; struct pci_dev *pci_dev; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index fadd264b64c3..631efce3a6ce 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -319,6 +319,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) /* install notify handler */ if (bridge->type != BRIDGE_TYPE_HOST) { + if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { + status = acpi_remove_notify_handler(bridge->func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + } status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, @@ -331,6 +338,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) } +/* find acpiphp_func from acpiphp_bridge */ +static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) +{ + struct list_head *node, *l; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + struct acpiphp_func *func; + + list_for_each(node, &bridge_list) { + bridge = list_entry(node, struct acpiphp_bridge, list); + for (slot = bridge->slots; slot; slot = slot->next) { + list_for_each(l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, + sibling); + if (func->handle == handle) + return func; + } + } + } + + return NULL; +} + + +static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) +{ + acpi_handle dummy_handle; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_STA", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_STA; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_EJ0", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_EJ0; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_PS0", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_PS0; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_PS3", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_PS3; + + /* is this ejectable p2p bridge? */ + if (bridge->flags & BRIDGE_HAS_EJ0) { + struct acpiphp_func *func; + + dbg("found ejectable p2p bridge\n"); + + /* make link between PCI bridge and PCI function */ + func = acpiphp_bridge_handle_to_function(bridge->handle); + if (!func) + return; + bridge->func = func; + func->bridge = bridge; + } +} + + /* allocate and initialize host bridge data structure */ static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) { @@ -364,6 +431,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) bridge->type = BRIDGE_TYPE_P2P; bridge->handle = handle; + config_p2p_bridge_flags(bridge); bridge->pci_dev = pci_dev_get(pci_dev); bridge->pci_bus = pci_dev->subordinate; @@ -423,7 +491,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, find_p2p_bridge, dev->subordinate, NULL); if (ACPI_FAILURE(status)) - warn("find_p2p_bridge faied (error code = 0x%x)\n", status); + warn("find_p2p_bridge failed (error code = 0x%x)\n", status); out: pci_dev_put(dev); @@ -486,7 +554,7 @@ static int add_bridge(acpi_handle handle) find_p2p_bridge, pci_bus, NULL); if (ACPI_FAILURE(status)) - warn("find_p2p_bridge faied (error code = 0x%x)\n",status); + warn("find_p2p_bridge failed (error code = 0x%x)\n", status); return 0; } @@ -516,6 +584,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); + if ((bridge->type != BRIDGE_TYPE_HOST) && + ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { + status = acpi_install_notify_handler(bridge->func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func, + bridge->func); + if (ACPI_FAILURE(status)) + err("failed to install interrupt notify handler\n"); + } + slot = bridge->slots; while (slot) { struct acpiphp_slot *next = slot->next; @@ -549,6 +627,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) { struct acpiphp_bridge *bridge; + /* cleanup p2p bridges under this P2P bridge + in a depth-first manner */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, + cleanup_p2p_bridge, NULL, NULL); + if (!(bridge = acpiphp_handle_to_bridge(handle))) return AE_OK; cleanup_bridge(bridge); @@ -559,15 +642,14 @@ static void remove_bridge(acpi_handle handle) { struct acpiphp_bridge *bridge; + /* cleanup p2p bridges under this host bridge + in a depth-first manner */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + (u32)1, cleanup_p2p_bridge, NULL, NULL); + bridge = acpiphp_handle_to_bridge(handle); - if (bridge) { + if (bridge) cleanup_bridge(bridge); - } else { - /* clean-up p2p bridges under this host bridge */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, cleanup_p2p_bridge, - NULL, NULL); - } } static struct pci_dev * get_apic_pci_info(acpi_handle handle) @@ -881,6 +963,7 @@ static int enable_device(struct acpiphp_slot *slot) struct acpiphp_func *func; int retval = 0; int num, max, pass; + acpi_status status; if (slot->flags & SLOT_ENABLED) goto err_exit; @@ -933,6 +1016,17 @@ static int enable_device(struct acpiphp_slot *slot) func = list_entry(l, struct acpiphp_func, sibling); func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, func->function)); + if (!func->pci_dev) + continue; + + if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && + func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) + continue; + + status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); + if (ACPI_FAILURE(status)) + warn("find_p2p_bridge failed (error code = 0x%x)\n", + status); } slot->flags |= SLOT_ENABLED; @@ -958,6 +1052,13 @@ static int disable_device(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); + if (func->bridge) { + /* cleanup p2p bridges under this P2P bridge */ + cleanup_p2p_bridge(func->bridge->handle, + (u32)1, NULL, NULL); + func->bridge = NULL; + } + acpiphp_bus_trim(func->handle); /* try to remove anyway. * acpiphp_bus_add might have been failed */ @@ -1292,6 +1393,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + if ((bridge->type != BRIDGE_TYPE_HOST) && + (bridge->flags & BRIDGE_HAS_EJ0)) { + struct acpiphp_slot *slot; + slot = bridge->func->slot; + if (!acpiphp_disable_slot(slot)) + acpiphp_eject_slot(slot); + } break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: -- cgit v1.2.2 From c14424736e76f3d8477a41de531e6b5dcce3d5b0 Mon Sep 17 00:00:00 2001 From: MUNEDA Takahiro Date: Wed, 22 Mar 2006 14:49:27 +0900 Subject: [PATCH] acpiphp: host and p2p hotplug I encountered the problem that when there are some hotplug slots are under the host bridge, the hotplug slots under the p2p bridge are not treated as hotpluggable. This patch fixes this BUG. Signed-off-by: MUNEDA Takahiro Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 631efce3a6ce..bbe27c16bc3d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -546,7 +546,6 @@ static int add_bridge(acpi_handle handle) if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); add_host_bridge(handle, pci_bus); - return 0; } /* search P2P bridges under this host bridge */ -- cgit v1.2.2 From cde0e5d722c77d1194f40de54a99c90afe365480 Mon Sep 17 00:00:00 2001 From: MUNEDA Takahiro Date: Wed, 22 Mar 2006 14:49:33 +0900 Subject: [PATCH] acpiphp: turn off slot power at error case When acpiphp_enable_slot() is failed, acpiphp does not change the slot->flags. Therefore, when user tries to read power status, acpiphp_get_power_status() returns the enable status whether the slot is not really enabled. This patch fixes this BUG. Signed-off-by: MUNEDA Takahiro Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bbe27c16bc3d..610a530232ff 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1592,9 +1592,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; - if (get_slot_status(slot) == ACPI_STA_ALL) + if (get_slot_status(slot) == ACPI_STA_ALL) { /* configure all functions */ retval = enable_device(slot); + if (retval) + power_off_slot(slot); + } else { + dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__); + power_off_slot(slot); + } err_exit: mutex_unlock(&slot->crit_sect); -- cgit v1.2.2 From 81b26bcacd5df0f65344fb430b1bf7fe9cfbfe2a Mon Sep 17 00:00:00 2001 From: Kristen Accardi Date: Tue, 18 Apr 2006 14:36:43 -0700 Subject: [PATCH] PCI Hotplug: don't use acpi_os_free acpi_os_free should not be used by drivers outside of acpi/*/*.c. Replace with kfree(). Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 16 ++++++++-------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 39af9c325f35..64cb30d7fc9a 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -58,7 +58,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) if (!ret_buf.pointer) { printk(KERN_ERR "%s:%s alloc for _HPP fail\n", __FUNCTION__, (char *)string.pointer); - acpi_os_free(string.pointer); + kfree(string.pointer); return AE_NO_MEMORY; } status = acpi_evaluate_object(handle, METHOD_NAME__HPP, @@ -69,7 +69,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) if (ACPI_FAILURE(status)) { pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__, (char *)string.pointer, status); - acpi_os_free(string.pointer); + kfree(string.pointer); return status; } } @@ -109,8 +109,8 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); free_and_return: - acpi_os_free(string.pointer); - acpi_os_free(ret_buf.pointer); + kfree(string.pointer); + kfree(ret_buf.pointer); return status; } @@ -136,7 +136,7 @@ acpi_status acpi_run_oshp(acpi_handle handle) pr_debug("%s:%s OSHP passes\n", __FUNCTION__, (char *)string.pointer); - acpi_os_free(string.pointer); + kfree(string.pointer); return status; } EXPORT_SYMBOL_GPL(acpi_run_oshp); @@ -192,19 +192,19 @@ int acpi_root_bridge(acpi_handle handle) if ((info->valid & ACPI_VALID_HID) && !strcmp(PCI_ROOT_HID_STRING, info->hardware_id.value)) { - acpi_os_free(buffer.pointer); + kfree(buffer.pointer); return 1; } if (info->valid & ACPI_VALID_CID) { for (i=0; i < info->compatibility_id.count; i++) { if (!strcmp(PCI_ROOT_HID_STRING, info->compatibility_id.id[i].value)) { - acpi_os_free(buffer.pointer); + kfree(buffer.pointer); return 1; } } } - acpi_os_free(buffer.pointer); + kfree(buffer.pointer); } return 0; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 610a530232ff..2a83e6bdab6a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -715,7 +715,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base) break; } out: - acpi_os_free(buffer.pointer); + kfree(buffer.pointer); return result; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6c14d9e46b2e..7f459dfeadd3 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1288,7 +1288,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) if (ACPI_SUCCESS(status)) { dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), (char *)string.pointer); - acpi_os_free(string.pointer); + kfree(string.pointer); return 0; } if (acpi_root_bridge(handle)) @@ -1302,7 +1302,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) err("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); - acpi_os_free(string.pointer); + kfree(string.pointer); return -1; } #endif -- cgit v1.2.2 From 2433ee2654f0ac86f7886e5a8d01bee7f3c7c6db Mon Sep 17 00:00:00 2001 From: Kristen Accardi Date: Mon, 24 Apr 2006 15:50:59 -0700 Subject: [PATCH] pciehp: dont call pci_enable_dev Don't call pci_enable_device from pciehp because the pcie port service driver already does this. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7f459dfeadd3..081dfef4fe62 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1404,9 +1404,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); - if (pci_enable_device(pdev)) - goto abort_free_ctlr; - mutex_init(&ctrl->crit_sect); /* setup wait queue */ init_waitqueue_head(&ctrl->queue); -- cgit v1.2.2 From 7430e34c70106a9576fc61d77604d164b187a1b7 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 10:54:50 +0900 Subject: [PATCH] acpi_pcihp: Fix programming _HPP values This patch fixes the problem that hotplug parameters are not programed when PCI cards are hot-added by ACPIPHP, SHPCHP and PCIEHP driver. The pci_dev structure being hot-added is not bound to ACPI handle, so we need to trace PCI bus tree to find ACPI handle. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 34 ++++++++++++++++++++++++---------- drivers/pci/hotplug/acpiphp_glue.c | 3 ++- drivers/pci/hotplug/pci_hotplug.h | 2 +- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/shpchp.h | 2 +- 5 files changed, 29 insertions(+), 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 64cb30d7fc9a..9395fec73423 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -145,14 +145,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp); /* acpi_get_hp_params_from_firmware * - * @dev - the pci_dev of the newly added device + * @bus - the pci_bus of the bus on which the device is newly added * @hpp - allocated by the caller */ -acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, +acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp) { acpi_status status = AE_NOT_FOUND; - struct pci_dev *pdev = dev; + acpi_handle handle, phandle; + struct pci_bus *pbus = bus; + struct pci_dev *pdev; + + do { + pdev = pbus->self; + if (!pdev) { + handle = acpi_get_pci_rootbridge_handle( + pci_domain_nr(pbus), pbus->number); + break; + } + handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); + pbus = pbus->parent; + } while (!handle); /* * _HPP settings apply to all child buses, until another _HPP is @@ -160,15 +173,16 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, * look for it in the parent device scope since that would apply to * this pci dev. If we don't find any _HPP, use hardcoded defaults */ - while (pdev && (ACPI_FAILURE(status))) { - acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); - if (!handle) - break; + while (handle) { status = acpi_run_hpp(handle, hpp); - if (!(pdev->bus->parent)) + if (ACPI_SUCCESS(status)) + break; + if (acpi_root_bridge(handle)) + break; + status = acpi_get_parent(handle, &phandle); + if (ACPI_FAILURE(status)) break; - /* Check if a parent object supports _HPP */ - pdev = pdev->bus->parent->self; + handle = phandle; } return status; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 2a83e6bdab6a..4b0988e93806 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -286,7 +286,7 @@ static void decode_hpp(struct acpiphp_bridge *bridge) { acpi_status status; - status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp); + status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp); if (ACPI_FAILURE(status)) { /* use default numbers */ bridge->hpp.cache_line_size = 0x10; @@ -1250,6 +1250,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) memset(&bridge, 0, sizeof(bridge)); bridge.handle = handle; + bridge.pci_bus = bus; bridge.pci_dev = bus->self; decode_hpp(&bridge); list_for_each_entry(dev, &bus->devices, bus_list) diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h index eb0d01d47236..6913ace70e9b 100644 --- a/drivers/pci/hotplug/pci_hotplug.h +++ b/drivers/pci/hotplug/pci_hotplug.h @@ -188,7 +188,7 @@ struct hotplug_params { #include #include extern acpi_status acpi_run_oshp(acpi_handle handle); -extern acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, +extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp); int acpi_root_bridge(acpi_handle handle); #endif diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 92c1f0f1e1ad..ce89f5815861 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -284,7 +284,7 @@ struct hpc_ops { static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp) { - if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp))) + if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp))) return -ENODEV; return 0; } diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 5c70f43908c4..b70fddbce934 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -196,7 +196,7 @@ extern void queue_pushbutton_work(void *data); static inline int get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp) { - if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp))) + if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp))) return -ENODEV; return 0; } -- cgit v1.2.2 From aad20cabaa3d6dfa1e0ebc8fb0537a96d3518b8f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 10 May 2006 22:20:34 +0900 Subject: [PATCH] acpi_pcihp: Remove improper error message about OSHP This patch converts the improper error message about OSHP evaluation to debug message which is displayed only when pci_hotplug.ko is loaded with debugging mode enabled. To do this, this patch adds a new module parameter "debug_acpi" to pci_hotplug.ko for enabling/disabling debug messages in acpi_pcihp.c. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 9395fec73423..afac5c37325b 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -33,10 +34,19 @@ #include #include "pci_hotplug.h" +#define MY_NAME "acpi_pcihp" + +#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + #define METHOD_NAME__SUN "_SUN" #define METHOD_NAME__HPP "_HPP" #define METHOD_NAME_OSHP "OSHP" +static int debug_acpi; + static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) @@ -130,8 +140,12 @@ acpi_status acpi_run_oshp(acpi_handle handle) /* run OSHP */ status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); if (ACPI_FAILURE(status)) - printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__, - (char *)string.pointer, status); + if (status != AE_NOT_FOUND) + printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", + __FUNCTION__, (char *)string.pointer, status); + else + dbg("%s:%s OSHP not found\n", + __FUNCTION__, (char *)string.pointer); else pr_debug("%s:%s OSHP passes\n", __FUNCTION__, (char *)string.pointer); @@ -223,3 +237,6 @@ int acpi_root_bridge(acpi_handle handle) return 0; } EXPORT_SYMBOL_GPL(acpi_root_bridge); + +module_param(debug_acpi, bool, 0644); +MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); -- cgit v1.2.2 From e22b73501608901bab7ee9b1f8cb67f15e8efb7a Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 10:57:14 +0900 Subject: [PATCH] acpi_pcihp: Add support for _HPX This patch adds support for _HPX (Hot Plug Parameter Extensions) defined in ACPI3.0a spec. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 188 +++++++++++++++++++++++++++++++++++-- drivers/pci/hotplug/acpiphp_glue.c | 31 +++--- drivers/pci/hotplug/pci_hotplug.h | 48 +++++++++- drivers/pci/hotplug/shpchp_pci.c | 31 +++--- 4 files changed, 262 insertions(+), 36 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index afac5c37325b..51cb9f817c22 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -47,6 +47,171 @@ static int debug_acpi; +static acpi_status +decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 6) + return AE_ERROR; + for (i = 2; i < 6; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t0 = &hpx->type0_data; + hpx->t0->revision = revision; + hpx->t0->cache_line_size = fields[2].integer.value; + hpx->t0->latency_timer = fields[3].integer.value; + hpx->t0->enable_serr = fields[4].integer.value; + hpx->t0->enable_perr = fields[5].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 0 Revision %d record not supported\n", + __FUNCTION__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 5) + return AE_ERROR; + for (i = 2; i < 5; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t1 = &hpx->type1_data; + hpx->t1->revision = revision; + hpx->t1->max_mem_read = fields[2].integer.value; + hpx->t1->avg_max_split = fields[3].integer.value; + hpx->t1->tot_max_split = fields[4].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 1 Revision %d record not supported\n", + __FUNCTION__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) +{ + int i; + union acpi_object *fields = record->package.elements; + u32 revision = fields[1].integer.value; + + switch (revision) { + case 1: + if (record->package.count != 18) + return AE_ERROR; + for (i = 2; i < 18; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + hpx->t2 = &hpx->type2_data; + hpx->t2->revision = revision; + hpx->t2->unc_err_mask_and = fields[2].integer.value; + hpx->t2->unc_err_mask_or = fields[3].integer.value; + hpx->t2->unc_err_sever_and = fields[4].integer.value; + hpx->t2->unc_err_sever_or = fields[5].integer.value; + hpx->t2->cor_err_mask_and = fields[6].integer.value; + hpx->t2->cor_err_mask_or = fields[7].integer.value; + hpx->t2->adv_err_cap_and = fields[8].integer.value; + hpx->t2->adv_err_cap_or = fields[9].integer.value; + hpx->t2->pci_exp_devctl_and = fields[10].integer.value; + hpx->t2->pci_exp_devctl_or = fields[11].integer.value; + hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; + hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; + hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; + hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; + hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; + hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; + break; + default: + printk(KERN_WARNING + "%s: Type 2 Revision %d record not supported\n", + __FUNCTION__, revision); + return AE_ERROR; + } + return AE_OK; +} + +static acpi_status +acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) +{ + acpi_status status; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *package, *record, *fields; + u32 type; + int i; + + /* Clear the return buffer with zeros */ + memset(hpx, 0, sizeof(struct hotplug_params)); + + status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); + if (ACPI_FAILURE(status)) + return status; + + package = (union acpi_object *)buffer.pointer; + if (package->type != ACPI_TYPE_PACKAGE) { + status = AE_ERROR; + goto exit; + } + + for (i = 0; i < package->package.count; i++) { + record = &package->package.elements[i]; + if (record->type != ACPI_TYPE_PACKAGE) { + status = AE_ERROR; + goto exit; + } + + fields = record->package.elements; + if (fields[0].type != ACPI_TYPE_INTEGER || + fields[1].type != ACPI_TYPE_INTEGER) { + status = AE_ERROR; + goto exit; + } + + type = fields[0].integer.value; + switch (type) { + case 0: + status = decode_type0_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + case 1: + status = decode_type1_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + case 2: + status = decode_type2_hpx_record(record, hpx); + if (ACPI_FAILURE(status)) + goto exit; + break; + default: + printk(KERN_ERR "%s: Type %d record not supported\n", + __FUNCTION__, type); + status = AE_ERROR; + goto exit; + } + } + exit: + kfree(buffer.pointer); + return status; +} static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) @@ -60,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); + /* Clear the return buffer with zeros */ + memset(hpp, 0, sizeof(struct hotplug_params)); + /* get _hpp */ status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); switch (status) { @@ -108,15 +276,16 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) } } - hpp->cache_line_size = nui[0]; - hpp->latency_timer = nui[1]; - hpp->enable_serr = nui[2]; - hpp->enable_perr = nui[3]; + hpp->t0 = &hpp->type0_data; + hpp->t0->cache_line_size = nui[0]; + hpp->t0->latency_timer = nui[1]; + hpp->t0->enable_serr = nui[2]; + hpp->t0->enable_perr = nui[3]; - pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); - pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer); - pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); - pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); + pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->t0->cache_line_size); + pr_debug(" _HPP: latency timer =0x%x\n", hpp->t0->latency_timer); + pr_debug(" _HPP: enable SERR =0x%x\n", hpp->t0->enable_serr); + pr_debug(" _HPP: enable PERR =0x%x\n", hpp->t0->enable_perr); free_and_return: kfree(string.pointer); @@ -188,6 +357,9 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, * this pci dev. If we don't find any _HPP, use hardcoded defaults */ while (handle) { + status = acpi_run_hpx(handle, hpp); + if (ACPI_SUCCESS(status)) + break; status = acpi_run_hpp(handle, hpp); if (ACPI_SUCCESS(status)) break; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 4b0988e93806..d370f999782e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -287,12 +287,18 @@ static void decode_hpp(struct acpiphp_bridge *bridge) acpi_status status; status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status) || + !bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) { /* use default numbers */ - bridge->hpp.cache_line_size = 0x10; - bridge->hpp.latency_timer = 0x40; - bridge->hpp.enable_serr = 0; - bridge->hpp.enable_perr = 0; + printk(KERN_WARNING + "%s: Could not get hotplug parameters. Use defaults\n", + __FUNCTION__); + bridge->hpp.t0 = &bridge->hpp.type0_data; + bridge->hpp.t0->revision = 0; + bridge->hpp.t0->cache_line_size = 0x10; + bridge->hpp.t0->latency_timer = 0x40; + bridge->hpp.t0->enable_serr = 0; + bridge->hpp.t0->enable_perr = 0; } } @@ -1206,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) return; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); + bridge->hpp.t0->cache_line_size); pci_write_config_byte(dev, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); + bridge->hpp.t0->latency_timer); pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); - if (bridge->hpp.enable_serr) + if (bridge->hpp.t0->enable_serr) pci_cmd |= PCI_COMMAND_SERR; else pci_cmd &= ~PCI_COMMAND_SERR; - if (bridge->hpp.enable_perr) + if (bridge->hpp.t0->enable_perr) pci_cmd |= PCI_COMMAND_PARITY; else pci_cmd &= ~PCI_COMMAND_PARITY; @@ -1224,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) /* Program bridge control value and child devices */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, - bridge->hpp.latency_timer); + bridge->hpp.t0->latency_timer); pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); - if (bridge->hpp.enable_serr) + if (bridge->hpp.t0->enable_serr) pci_bctl |= PCI_BRIDGE_CTL_SERR; else pci_bctl &= ~PCI_BRIDGE_CTL_SERR; - if (bridge->hpp.enable_perr) + if (bridge->hpp.t0->enable_perr) pci_bctl |= PCI_BRIDGE_CTL_PARITY; else pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h index 6913ace70e9b..e929b7c11429 100644 --- a/drivers/pci/hotplug/pci_hotplug.h +++ b/drivers/pci/hotplug/pci_hotplug.h @@ -176,11 +176,51 @@ extern int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info); extern struct subsystem pci_hotplug_slots_subsys; +/* PCI Setting Record (Type 0) */ +struct hpp_type0 { + u32 revision; + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + +/* PCI-X Setting Record (Type 1) */ +struct hpp_type1 { + u32 revision; + u8 max_mem_read; + u8 avg_max_split; + u16 tot_max_split; +}; + +/* PCI Express Setting Record (Type 2) */ +struct hpp_type2 { + u32 revision; + u32 unc_err_mask_and; + u32 unc_err_mask_or; + u32 unc_err_sever_and; + u32 unc_err_sever_or; + u32 cor_err_mask_and; + u32 cor_err_mask_or; + u32 adv_err_cap_and; + u32 adv_err_cap_or; + u16 pci_exp_devctl_and; + u16 pci_exp_devctl_or; + u16 pci_exp_lnkctl_and; + u16 pci_exp_lnkctl_or; + u32 sec_unc_err_sever_and; + u32 sec_unc_err_sever_or; + u32 sec_unc_err_mask_and; + u32 sec_unc_err_mask_or; +}; + struct hotplug_params { - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; + struct hpp_type0 *t0; /* Type0: NULL if not available */ + struct hpp_type1 *t1; /* Type1: NULL if not available */ + struct hpp_type2 *t2; /* Type2: NULL if not available */ + struct hpp_type0 type0_data; + struct hpp_type1 type1_data; + struct hpp_type2 type2_data; }; #ifdef CONFIG_ACPI diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 257adc233996..0a6b25ef194c 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -47,21 +47,28 @@ static void program_fw_provided_values(struct pci_dev *dev) return; /* use default values if we can't get them from firmware */ - if (get_hp_params_from_firmware(dev, &hpp)) { - hpp.cache_line_size = 8; - hpp.latency_timer = 0x40; - hpp.enable_serr = 0; - hpp.enable_perr = 0; + if (get_hp_params_from_firmware(dev, &hpp) || + !hpp.t0 || (hpp.t0->revision > 1)) { + printk(KERN_WARNING + "%s: Could not get hotplug parameters. Use defaults\n", + __FUNCTION__); + hpp.t0 = &hpp.type0_data; + hpp.t0->revision = 0; + hpp.t0->cache_line_size = 8; + hpp.t0->latency_timer = 0x40; + hpp.t0->enable_serr = 0; + hpp.t0->enable_perr = 0; } - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); + pci_write_config_byte(dev, + PCI_CACHE_LINE_SIZE, hpp.t0->cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.t0->latency_timer); pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); - if (hpp.enable_serr) + if (hpp.t0->enable_serr) pci_cmd |= PCI_COMMAND_SERR; else pci_cmd &= ~PCI_COMMAND_SERR; - if (hpp.enable_perr) + if (hpp.t0->enable_perr) pci_cmd |= PCI_COMMAND_PARITY; else pci_cmd &= ~PCI_COMMAND_PARITY; @@ -70,13 +77,13 @@ static void program_fw_provided_values(struct pci_dev *dev) /* Program bridge control value and child devices */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, - hpp.latency_timer); + hpp.t0->latency_timer); pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); - if (hpp.enable_serr) + if (hpp.t0->enable_serr) pci_bctl |= PCI_BRIDGE_CTL_SERR; else pci_bctl &= ~PCI_BRIDGE_CTL_SERR; - if (hpp.enable_perr) + if (hpp.t0->enable_perr) pci_bctl |= PCI_BRIDGE_CTL_PARITY; else pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; -- cgit v1.2.2 From 40abb96c51bbcb06785e233e96f40c35657ade83 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 8 May 2006 18:34:09 +0900 Subject: [PATCH] pciehp: Fix programming hotplug parameters Current PCHEHP driver doesn't have any code to program hotplug parameters from firmware. So hotplug parameters are never programed at hot-add time. This patch add support for programming hotplug parameters to PCIEHP driver. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 141 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 4017fb03a0b8..6aa6a1be4555 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -34,6 +34,144 @@ #include "../pci.h" #include "pciehp.h" +static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) +{ + u16 pci_cmd, pci_bctl; + + if (hpp->revision > 1) { + printk(KERN_WARNING "%s: Rev.%d type0 record not supported\n", + __FUNCTION__, hpp->revision); + return; + } + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer); + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + if (hpp->enable_serr) + pci_cmd |= PCI_COMMAND_SERR; + else + pci_cmd &= ~PCI_COMMAND_SERR; + if (hpp->enable_perr) + pci_cmd |= PCI_COMMAND_PARITY; + else + pci_cmd &= ~PCI_COMMAND_PARITY; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Program bridge control value */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, + hpp->latency_timer); + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); + if (hpp->enable_serr) + pci_bctl |= PCI_BRIDGE_CTL_SERR; + else + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; + if (hpp->enable_perr) + pci_bctl |= PCI_BRIDGE_CTL_PARITY; + else + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); + } +} + +static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) +{ + int pos; + u16 reg16; + u32 reg32; + + if (hpp->revision > 1) { + printk(KERN_WARNING "%s: Rev.%d type2 record not supported\n", + __FUNCTION__, hpp->revision); + return; + } + + /* Find PCI Express capability */ + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return; + + /* Initialize Device Control Register */ + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, ®16); + reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or; + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16); + + /* Initialize Link Control Register */ + if (dev->subordinate) { + pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, ®16); + reg16 = (reg16 & hpp->pci_exp_lnkctl_and) + | hpp->pci_exp_lnkctl_or; + pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16); + } + + /* Find Advanced Error Reporting Enhanced Capability */ + pos = 256; + do { + pci_read_config_dword(dev, pos, ®32); + if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) + break; + } while ((pos = PCI_EXT_CAP_NEXT(reg32))); + if (!pos) + return; + + /* Initialize Uncorrectable Error Mask Register */ + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); + reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); + + /* Initialize Uncorrectable Error Severity Register */ + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); + reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); + + /* Initialize Correctable Error Mask Register */ + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); + reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; + pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); + + /* Initialize Advanced Error Capabilities and Control Register */ + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + /* + * FIXME: The following two registers are not supported yet. + * + * o Secondary Uncorrectable Error Severity Register + * o Secondary Uncorrectable Error Mask Register + */ +} + +static void program_fw_provided_values(struct pci_dev *dev) +{ + struct pci_dev *cdev; + struct hotplug_params hpp; + + /* Program hpp values for this device */ + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + + if (pciehp_get_hp_params_from_firmware(dev, &hpp)) { + printk(KERN_WARNING "%s: Could not get hotplug parameters\n", + __FUNCTION__); + return; + } + + if (hpp.t2) + program_hpp_type2(dev, hpp.t2); + if (hpp.t0) + program_hpp_type0(dev, hpp.t0); + + /* Program child devices */ + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + program_fw_provided_values(cdev); + } +} + static int pciehp_add_bridge(struct pci_dev *dev) { struct pci_bus *parent = dev->bus; @@ -92,8 +230,7 @@ int pciehp_configure_device(struct slot *p_slot) (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { pciehp_add_bridge(dev); } - /* TBD: program firmware provided _HPP values */ - /* program_fw_provided_values(dev); */ + program_fw_provided_values(dev); } pci_bus_assign_resources(parent); -- cgit v1.2.2 From 75d97c59a192ca0fe2577974dac0c16a73a377eb Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 11:08:42 +0900 Subject: [PATCH] SHPC: Cleanup SHPC register access This patch cleans up the code to access SHPC working register sets. This patch has no functional changes. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 192 +++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 80 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 66123cf4deaa..3abeb54964ae 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -208,6 +208,49 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); static int hpc_check_cmd_status(struct controller *ctrl); +static inline u8 shpc_readb(struct controller *ctrl, int reg) +{ + return readb(ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) +{ + writeb(val, ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline u16 shpc_readw(struct controller *ctrl, int reg) +{ + return readw(ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) +{ + writew(val, ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline u32 shpc_readl(struct controller *ctrl, int reg) +{ + return readl(ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) +{ + writel(val, ctrl->hpc_ctlr_handle->creg + reg); +} + +static inline int shpc_indirect_read(struct controller *ctrl, int index, + u32 *value) +{ + int rc; + u32 cap_offset = ctrl->cap_offset; + struct pci_dev *pdev = ctrl->pci_dev; + + rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); + if (rc) + return rc; + return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); +} + /* This is the interrupt polling timeout function. */ static void int_poll_timeout(unsigned long lphp_ctlr) { @@ -273,6 +316,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 cmd_status; int retval = 0; u16 temp_word; @@ -289,7 +333,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) } for (i = 0; i < 10; i++) { - cmd_status = readw(php_ctlr->creg + CMD_STATUS); + cmd_status = shpc_readw(ctrl, CMD_STATUS); if (!(cmd_status & 0x1)) break; @@ -297,7 +341,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) msleep(100); } - cmd_status = readw(php_ctlr->creg + CMD_STATUS); + cmd_status = shpc_readw(ctrl, CMD_STATUS); if (cmd_status & 0x1) { /* After 1 sec and and the controller is still busy */ @@ -314,7 +358,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) * command. */ slot->ctrl->cmd_busy = 1; - writew(temp_word, php_ctlr->creg + CMD); + shpc_writew(ctrl, CMD, temp_word); /* * Wait for command completion. @@ -338,7 +382,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) static int hpc_check_cmd_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u16 cmd_status; int retval = 0; @@ -349,7 +392,7 @@ static int hpc_check_cmd_status(struct controller *ctrl) return -1; } - cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; + cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; switch (cmd_status >> 1) { case 0: @@ -378,7 +421,7 @@ static int hpc_check_cmd_status(struct controller *ctrl) static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u32 slot_reg; u16 slot_status; u8 atten_led_state; @@ -390,7 +433,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return -1; } - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); slot_status = (u16) slot_reg; atten_led_state = (slot_status & 0x0030) >> 4; @@ -418,7 +461,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) static int hpc_get_power_status(struct slot * slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u32 slot_reg; u16 slot_status; u8 slot_state; @@ -431,7 +474,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) return -1; } - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); slot_status = (u16) slot_reg; slot_state = (slot_status & 0x0003); @@ -460,7 +503,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u32 slot_reg; u16 slot_status; @@ -471,7 +514,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return -1; } - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); slot_status = (u16)slot_reg; *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ @@ -483,7 +526,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u32 slot_reg; u16 slot_status; u8 card_state; @@ -495,7 +538,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) return -1; } - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); slot_status = (u16)slot_reg; card_state = (u8)((slot_status & 0x0C00) >> 10); *status = (card_state != 0x3) ? 1 : 0; @@ -506,7 +549,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; DBG_ENTER_ROUTINE @@ -515,7 +558,7 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) return -1; } - *prog_int = readb(php_ctlr->creg + PROG_INTERFACE); + *prog_int = shpc_readb(ctrl, PROG_INTERFACE); DBG_LEAVE_ROUTINE return 0; @@ -524,8 +567,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) { int retval = 0; - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg = readl(php_ctlr->creg + SLOT1 + 4 * slot->hp_slot); + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT1 + 4 * slot->hp_slot); u8 pcix_cap = (slot_reg >> 12) & 7; u8 m66_cap = (slot_reg >> 9) & 1; @@ -564,7 +607,7 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 sec_bus_status; u8 pi; int retval = 0; @@ -576,8 +619,8 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) return -1; } - pi = readb(php_ctlr->creg + PROG_INTERFACE); - sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + pi = shpc_readb(ctrl, PROG_INTERFACE); + sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); if (pi == 2) { *mode = (sec_bus_status & 0x0100) >> 8; @@ -593,7 +636,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) static int hpc_query_power_fault(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u32 slot_reg; u16 slot_status; u8 pwr_fault_state, status; @@ -605,7 +648,7 @@ static int hpc_query_power_fault(struct slot * slot) return -1; } - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); slot_status = (u16) slot_reg; pwr_fault_state = (slot_status & 0x0040) >> 7; status = (pwr_fault_state == 1) ? 0 : 1; @@ -724,7 +767,7 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, int *updown, /* physical_slot_num increament: 1 or -1 */ int *flags) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; + u32 slot_config; DBG_ENTER_ROUTINE @@ -733,12 +776,13 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, return -1; } - *first_device_num = php_ctlr->slot_device_offset; /* Obtained in shpc_init() */ - *num_ctlr_slots = php_ctlr->num_slots; /* Obtained in shpc_init() */ + slot_config = shpc_readl(ctrl, SLOT_CONFIG); + *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; + *num_ctlr_slots = slot_config & SLOT_NUM; + *physical_slot_num = (slot_config & PSN) >> 16; + *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; - *physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16; dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); - *updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1; DBG_LEAVE_ROUTINE return 0; @@ -761,7 +805,7 @@ static void hpc_release_ctlr(struct controller *ctrl) * Mask all slot event interrupts */ for (i = 0; i < ctrl->num_slots; i++) - writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i)); + shpc_writel(ctrl, SLOT1 + (4 * i), 0xffff3fff); cleanup_slots(ctrl); @@ -901,12 +945,12 @@ static int hpc_slot_disable(struct slot * slot) static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) { int retval; - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u8 pi, cmd; DBG_ENTER_ROUTINE - pi = readb(php_ctlr->creg + PROG_INTERFACE); + pi = shpc_readb(ctrl, PROG_INTERFACE); if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) return -EINVAL; @@ -992,7 +1036,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) return IRQ_NONE; /* Check to see if it was our interrupt */ - intr_loc = readl(php_ctlr->creg + INTR_LOC); + intr_loc = shpc_readl(ctrl, INTR_LOC); if (!intr_loc) return IRQ_NONE; @@ -1001,11 +1045,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if(!shpchp_poll_mode) { /* Mask Global Interrupt Mask - see implementation note on p. 139 */ /* of SHPC spec rev 1.0*/ - temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); temp_dword |= 0x00000001; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); - intr_loc2 = readl(php_ctlr->creg + INTR_LOC); + intr_loc2 = shpc_readl(ctrl, INTR_LOC); dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); } @@ -1015,9 +1059,9 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ - temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); temp_dword &= 0xfffdffff; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } @@ -1028,7 +1072,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { /* To find out which slot has interrupt pending */ if ((intr_loc >> hp_slot) & 0x01) { - temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); + temp_dword = shpc_readl(ctrl, SLOT1 + (4*hp_slot)); dbg("%s: Slot %x with intr, slot register = %x\n", __FUNCTION__, hp_slot, temp_dword); temp_byte = (temp_dword >> 16) & 0xFF; @@ -1047,18 +1091,18 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all slot events */ temp_dword = 0xe01f3fff; - writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + shpc_writel(ctrl, SLOT1 + (4*hp_slot), temp_dword); - intr_loc2 = readl(php_ctlr->creg + INTR_LOC); + intr_loc2 = shpc_readl(ctrl, INTR_LOC); dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); } } out: if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ - temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); temp_dword &= 0xfffffffe; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); } return IRQ_HANDLED; @@ -1067,11 +1111,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) { int retval = 0; - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; - u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); - u32 slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); - u32 slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); + u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); + u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); DBG_ENTER_ROUTINE @@ -1114,10 +1158,10 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) { int retval = 0; - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; - u16 sec_bus_reg = readw(php_ctlr->creg + SEC_BUS_CONFIG); - u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); + u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); DBG_ENTER_ROUTINE @@ -1206,19 +1250,6 @@ static struct hpc_ops shpchp_hpc_ops = { .release_ctlr = hpc_release_ctlr, }; -inline static int shpc_indirect_creg_read(struct controller *ctrl, int index, - u32 *value) -{ - int rc; - u32 cap_offset = ctrl->cap_offset; - struct pci_dev *pdev = ctrl->pci_dev; - - rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); - if (rc) - return rc; - return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); -} - int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; @@ -1227,7 +1258,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) u8 hp_slot; static int first = 1; u32 shpc_base_offset; - u32 tempdword, slot_reg; + u32 tempdword, slot_reg, slot_config; u8 i; DBG_ENTER_ROUTINE @@ -1257,13 +1288,13 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) } dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); - rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset); + rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); if (rc) { err("%s: cannot read base_offset\n", __FUNCTION__); goto abort_free_ctlr; } - rc = shpc_indirect_creg_read(ctrl, 3, &tempdword); + rc = shpc_indirect_read(ctrl, 3, &tempdword); if (rc) { err("%s: cannot read slot config\n", __FUNCTION__); goto abort_free_ctlr; @@ -1272,7 +1303,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); for (i = 0; i < 9 + num_slots; i++) { - rc = shpc_indirect_creg_read(ctrl, i, &tempdword); + rc = shpc_indirect_read(ctrl, i, &tempdword); if (rc) { err("%s: cannot read creg (index = %d)\n", __FUNCTION__, i); @@ -1326,29 +1357,33 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) php_ctlr->power_fault_callback = shpchp_handle_power_fault; php_ctlr->callback_instance_id = instance_id; + ctrl->hpc_ctlr_handle = php_ctlr; + ctrl->hpc_ops = &shpchp_hpc_ops; + /* Return PCI Controller Info */ - php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8; - php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM; + slot_config = shpc_readl(ctrl, SLOT_CONFIG); + php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; + php_ctlr->num_slots = slot_config & SLOT_NUM; dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); tempdword = 0x0003000f; - writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); /* Mask the MRL sensor SERR Mask of individual slot in * Slot SERR-INT Mask & clear all the existing event if any */ for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot ); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); tempdword = 0xffff3fff; - writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword); } if (shpchp_poll_mode) {/* Install interrupt polling code */ @@ -1392,24 +1427,21 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) } spin_unlock(&list_lock); - ctlr_seq_num++; - ctrl->hpc_ctlr_handle = php_ctlr; - ctrl->hpc_ops = &shpchp_hpc_ops; for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); + slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot ); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); tempdword = 0xe01f3fff; - writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword); } if (!shpchp_poll_mode) { /* Unmask all general input interrupts and SERR */ - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); tempdword = 0x0000000a; - writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); } -- cgit v1.2.2 From 2b34da7e61383b4b7773d2d4e776e58725794347 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 11:09:42 +0900 Subject: [PATCH] SHPC: Cleanup SHPC Logical Slot Register access This patch cleans up the code to access slot logical registers. This patch has no functional changes. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 3abeb54964ae..a5337cf1436d 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -90,6 +90,11 @@ #define MRLSENSOR 0x40000000 #define ATTN_BUTTON 0x80000000 +/* + * Logical Slot Register definitions + */ +#define SLOT_REG(i) (SLOT1 + (4 * i)) + /* Slot Status Field Definitions */ /* Slot State */ #define PWR_ONLY 0x0001 @@ -433,7 +438,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return -1; } - slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); slot_status = (u16) slot_reg; atten_led_state = (slot_status & 0x0030) >> 4; @@ -474,7 +479,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) return -1; } - slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); slot_status = (u16) slot_reg; slot_state = (slot_status & 0x0003); @@ -514,7 +519,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return -1; } - slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); slot_status = (u16)slot_reg; *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ @@ -538,7 +543,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) return -1; } - slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); slot_status = (u16)slot_reg; card_state = (u8)((slot_status & 0x0C00) >> 10); *status = (card_state != 0x3) ? 1 : 0; @@ -568,7 +573,7 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) { int retval = 0; struct controller *ctrl = slot->ctrl; - u32 slot_reg = shpc_readl(ctrl, SLOT1 + 4 * slot->hp_slot); + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); u8 pcix_cap = (slot_reg >> 12) & 7; u8 m66_cap = (slot_reg >> 9) & 1; @@ -648,7 +653,7 @@ static int hpc_query_power_fault(struct slot * slot) return -1; } - slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot)); + slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); slot_status = (u16) slot_reg; pwr_fault_state = (slot_status & 0x0040) >> 7; status = (pwr_fault_state == 1) ? 0 : 1; @@ -805,7 +810,7 @@ static void hpc_release_ctlr(struct controller *ctrl) * Mask all slot event interrupts */ for (i = 0; i < ctrl->num_slots; i++) - shpc_writel(ctrl, SLOT1 + (4 * i), 0xffff3fff); + shpc_writel(ctrl, SLOT_REG(i), 0xffff3fff); cleanup_slots(ctrl); @@ -1072,7 +1077,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { /* To find out which slot has interrupt pending */ if ((intr_loc >> hp_slot) & 0x01) { - temp_dword = shpc_readl(ctrl, SLOT1 + (4*hp_slot)); + temp_dword = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Slot %x with intr, slot register = %x\n", __FUNCTION__, hp_slot, temp_dword); temp_byte = (temp_dword >> 16) & 0xFF; @@ -1091,7 +1096,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all slot events */ temp_dword = 0xe01f3fff; - shpc_writel(ctrl, SLOT1 + (4*hp_slot), temp_dword); + shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); intr_loc2 = shpc_readl(ctrl, INTR_LOC); dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); @@ -1379,11 +1384,11 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) * Slot SERR-INT Mask & clear all the existing event if any */ for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { - slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot ); + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); tempdword = 0xffff3fff; - shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword); + shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); } if (shpchp_poll_mode) {/* Install interrupt polling code */ @@ -1430,11 +1435,11 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctlr_seq_num++; for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { - slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot ); + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); tempdword = 0xe01f3fff; - shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword); + shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); } if (!shpchp_poll_mode) { /* Unmask all general input interrupts and SERR */ -- cgit v1.2.2 From 5858759c2098c6792af1afa6d5ded94044740f9c Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 11:10:37 +0900 Subject: [PATCH] SHPC: Cleanup SHPC Logical Slot Register bits access This patch cleans up the code to access bits in slot logical registers. This patch has no functional change. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 151 +++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 87 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index a5337cf1436d..9731ee8224f2 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -95,43 +95,40 @@ */ #define SLOT_REG(i) (SLOT1 + (4 * i)) -/* Slot Status Field Definitions */ -/* Slot State */ -#define PWR_ONLY 0x0001 -#define ENABLED 0x0002 -#define DISABLED 0x0003 - -/* Power Indicator State */ -#define PWR_LED_ON 0x0004 -#define PWR_LED_BLINK 0x0008 -#define PWR_LED_OFF 0x000c - -/* Attention Indicator State */ -#define ATTEN_LED_ON 0x0010 -#define ATTEN_LED_BLINK 0x0020 -#define ATTEN_LED_OFF 0x0030 - -/* Power Fault */ -#define pwr_fault 0x0040 - -/* Attention Button */ -#define ATTEN_BUTTON 0x0080 - -/* MRL Sensor */ -#define MRL_SENSOR 0x0100 - -/* 66 MHz Capable */ -#define IS_66MHZ_CAP 0x0200 - -/* PRSNT1#/PRSNT2# */ -#define SLOT_EMP 0x0c00 - -/* PCI-X Capability */ -#define NON_PCIX 0x0000 -#define PCIX_66 0x1000 -#define PCIX_133 0x3000 -#define PCIX_266 0x4000 /* For PI = 2 only */ -#define PCIX_533 0x5000 /* For PI = 2 only */ +#define SLOT_STATE_SHIFT (0) +#define SLOT_STATE_MASK (3 << 0) +#define SLOT_STATE_PWRONLY (1) +#define SLOT_STATE_ENABLED (2) +#define SLOT_STATE_DISABLED (3) +#define PWR_LED_STATE_SHIFT (2) +#define PWR_LED_STATE_MASK (3 << 2) +#define ATN_LED_STATE_SHIFT (4) +#define ATN_LED_STATE_MASK (3 << 4) +#define ATN_LED_STATE_ON (1) +#define ATN_LED_STATE_BLINK (2) +#define ATN_LED_STATE_OFF (3) +#define POWER_FAULT (1 << 6) +#define ATN_BUTTON (1 << 7) +#define MRL_SENSOR (1 << 8) +#define MHZ66_CAP (1 << 9) +#define PRSNT_SHIFT (10) +#define PRSNT_MASK (3 << 10) +#define PCIX_CAP_SHIFT (12) +#define PCIX_CAP_MASK_PI1 (3 << 12) +#define PCIX_CAP_MASK_PI2 (7 << 12) +#define PRSNT_CHANGE_DETECTED (1 << 16) +#define ISO_PFAULT_DETECTED (1 << 17) +#define BUTTON_PRESS_DETECTED (1 << 18) +#define MRL_CHANGE_DETECTED (1 << 19) +#define CON_PFAULT_DETECTED (1 << 20) +#define PRSNT_CHANGE_INTR_MASK (1 << 24) +#define ISO_PFAULT_INTR_MASK (1 << 25) +#define BUTTON_PRESS_INTR_MASK (1 << 26) +#define MRL_CHANGE_INTR_MASK (1 << 27) +#define CON_PFAULT_INTR_MASK (1 << 28) +#define MRL_CHANGE_SERR_MASK (1 << 29) +#define CON_PFAULT_SERR_MASK (1 << 30) +#define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) /* SHPC 'write' operations/commands */ @@ -428,8 +425,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u32 slot_reg; - u16 slot_status; - u8 atten_led_state; + u8 state; DBG_ENTER_ROUTINE @@ -439,24 +435,20 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) } slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_status = (u16) slot_reg; - atten_led_state = (slot_status & 0x0030) >> 4; + state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; - switch (atten_led_state) { - case 0: - *status = 0xFF; /* Reserved */ - break; - case 1: + switch (state) { + case ATN_LED_STATE_ON: *status = 1; /* On */ break; - case 2: + case ATN_LED_STATE_BLINK: *status = 2; /* Blink */ break; - case 3: + case ATN_LED_STATE_OFF: *status = 0; /* Off */ break; default: - *status = 0xFF; + *status = 0xFF; /* Reserved */ break; } @@ -468,9 +460,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) { struct controller *ctrl = slot->ctrl; u32 slot_reg; - u16 slot_status; - u8 slot_state; - int retval = 0; + u8 state; DBG_ENTER_ROUTINE @@ -480,29 +470,25 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) } slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_status = (u16) slot_reg; - slot_state = (slot_status & 0x0003); + state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; - switch (slot_state) { - case 0: - *status = 0xFF; - break; - case 1: + switch (state) { + case SLOT_STATE_PWRONLY: *status = 2; /* Powered only */ break; - case 2: + case SLOT_STATE_ENABLED: *status = 1; /* Enabled */ break; - case 3: + case SLOT_STATE_DISABLED: *status = 0; /* Disabled */ break; default: - *status = 0xFF; + *status = 0xFF; /* Reserved */ break; } DBG_LEAVE_ROUTINE - return retval; + return 0; } @@ -510,7 +496,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u32 slot_reg; - u16 slot_status; DBG_ENTER_ROUTINE @@ -520,10 +505,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) } slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_status = (u16)slot_reg; - - *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ - + *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ DBG_LEAVE_ROUTINE return 0; @@ -533,8 +515,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u32 slot_reg; - u16 slot_status; - u8 card_state; + u8 state; DBG_ENTER_ROUTINE @@ -544,9 +525,8 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) } slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_status = (u16)slot_reg; - card_state = (u8)((slot_status & 0x0C00) >> 10); - *status = (card_state != 0x3) ? 1 : 0; + state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; + *status = (state != 0x3) ? 1 : 0; DBG_LEAVE_ROUTINE return 0; @@ -574,8 +554,8 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) int retval = 0; struct controller *ctrl = slot->ctrl; u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - u8 pcix_cap = (slot_reg >> 12) & 7; - u8 m66_cap = (slot_reg >> 9) & 1; + u8 pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; + u8 m66_cap = !!(slot_reg & MHZ66_CAP); DBG_ENTER_ROUTINE @@ -643,8 +623,6 @@ static int hpc_query_power_fault(struct slot * slot) { struct controller *ctrl = slot->ctrl; u32 slot_reg; - u16 slot_status; - u8 pwr_fault_state, status; DBG_ENTER_ROUTINE @@ -654,13 +632,10 @@ static int hpc_query_power_fault(struct slot * slot) } slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_status = (u16) slot_reg; - pwr_fault_state = (slot_status & 0x0040) >> 7; - status = (pwr_fault_state == 1) ? 0 : 1; DBG_LEAVE_ROUTINE /* Note: Logic 0 => fault */ - return status; + return !(slot_reg & POWER_FAULT); } static int hpc_set_attention_status(struct slot *slot, u8 value) @@ -1019,7 +994,6 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) struct controller *ctrl = NULL; struct php_ctlr_state_s *php_ctlr; u8 schedule_flag = 0; - u8 temp_byte; u32 temp_dword, intr_loc, intr_loc2; int hp_slot; @@ -1080,17 +1054,20 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) temp_dword = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Slot %x with intr, slot register = %x\n", __FUNCTION__, hp_slot, temp_dword); - temp_byte = (temp_dword >> 16) & 0xFF; - if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) + if ((php_ctlr->switch_change_callback) && + (temp_dword & MRL_CHANGE_DETECTED)) schedule_flag += php_ctlr->switch_change_callback( hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) + if ((php_ctlr->attention_button_callback) && + (temp_dword & BUTTON_PRESS_DETECTED)) schedule_flag += php_ctlr->attention_button_callback( hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) + if ((php_ctlr->presence_change_callback) && + (temp_dword & PRSNT_CHANGE_DETECTED)) schedule_flag += php_ctlr->presence_change_callback( hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12)) + if ((php_ctlr->power_fault_callback) && + (temp_dword & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))) schedule_flag += php_ctlr->power_fault_callback( hp_slot, php_ctlr->callback_instance_id); -- cgit v1.2.2 From 795eb5c4a73bee30e8c2dbb29174b329da56051c Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 11:11:54 +0900 Subject: [PATCH] SHPC: Fix SHPC Logical Slot Register bits access Current SHPCHP driver doesn't take care of RsvdP/RsvdZ[*] bits in logical slot registers. This might cause unpredicable results. This patch fixes this bug. [*] RsvdP and RsvdZ are defined in SHPC spec as follows: RsvdP - Reserved and Preserved. Register bits of this type are reserved for future use as R/W bits. The value read is undefined. Writes are ignored. Software must follow These rules when accessing RsvdP bits: - Software must ignore RsvdP bits when testing values read from these registers. - Software must not depend on RsvdP bit's ability to retain information when written - Software must always write back the value read in the RsvdP bits when writing one of these registers. RsvdZ - Reserved and Zero. Register bits of this type are reserved for future use as R/WC bits. The value read is undefined. Writes are ignored. Software must follow these rules when accessing RsvdZ bits: - Software must ignore RsvdZ bits when testing values read from these registers. - Software must not depends on a RsvdZ bit's ability to retain information when written. - Software must always write 0 to RsvdZ bits when writing one of these register. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 9731ee8224f2..285a21d36524 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -554,11 +554,25 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) int retval = 0; struct controller *ctrl = slot->ctrl; u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - u8 pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; u8 m66_cap = !!(slot_reg & MHZ66_CAP); + u8 pi, pcix_cap; DBG_ENTER_ROUTINE + if ((retval = hpc_get_prog_int(slot, &pi))) + return retval; + + switch (pi) { + case 1: + pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; + break; + case 2: + pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; + break; + default: + return -ENODEV; + } + dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", __FUNCTION__, slot_reg, pcix_cap, m66_cap); @@ -773,6 +787,7 @@ static void hpc_release_ctlr(struct controller *ctrl) struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *p, *p_prev; int i; + u32 slot_reg; DBG_ENTER_ROUTINE @@ -782,10 +797,17 @@ static void hpc_release_ctlr(struct controller *ctrl) } /* - * Mask all slot event interrupts + * Mask event interrupts and SERRs of all slots */ - for (i = 0; i < ctrl->num_slots; i++) - shpc_writel(ctrl, SLOT_REG(i), 0xffff3fff); + for (i = 0; i < ctrl->num_slots; i++) { + slot_reg = shpc_readl(ctrl, SLOT_REG(i)); + slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | + BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | + CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | + CON_PFAULT_SERR_MASK); + slot_reg &= ~SLOT_REG_RSVDZ_MASK; + shpc_writel(ctrl, SLOT_REG(i), slot_reg); + } cleanup_slots(ctrl); @@ -1072,7 +1094,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) hp_slot, php_ctlr->callback_instance_id); /* Clear all slot events */ - temp_dword = 0xe01f3fff; + temp_dword &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); intr_loc2 = shpc_readl(ctrl, INTR_LOC); @@ -1364,8 +1386,12 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); - tempdword = 0xffff3fff; - shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); + slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | + BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | + CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | + CON_PFAULT_SERR_MASK); + slot_reg &= ~SLOT_REG_RSVDZ_MASK; + shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } if (shpchp_poll_mode) {/* Install interrupt polling code */ @@ -1411,12 +1437,17 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctlr_seq_num++; + /* + * Unmask all event interrupts of all slots + */ for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); - tempdword = 0xe01f3fff; - shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); + slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | + BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | + CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); + shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } if (!shpchp_poll_mode) { /* Unmask all general input interrupts and SERR */ -- cgit v1.2.2 From e7138723692e43b7d43578746ad21bf194847527 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 May 2006 11:12:37 +0900 Subject: [PATCH] SHPC: Fix SHPC Contoller SERR-INT Register bits access Current SHPCHP driver doesn't take care of RsvdP/RsvdZ[*] bits in controller SERR-INT register. This might cause unpredicable results. This patch fixes this bug. [*] RsvdP and RsvdZ are defined in SHPC spec as follows: RsvdP - Reserved and Preserved. Register bits of this type are reserved for future use as R/W bits. The value read is undefined. Writes are ignored. Software must follow These rules when accessing RsvdP bits: - Software must ignore RsvdP bits when testing values read from these registers. - Software must not depend on RsvdP bit's ability to retain information when written - Software must always write back the value read in the RsvdP bits when writing one of these registers. RsvdZ - Reserved and Zero. Register bits of this type are reserved for future use as R/WC bits. The value read is undefined. Writes are ignored. Software must follow these rules when accessing RsvdZ bits: - Software must ignore RsvdZ bits when testing values read from these registers. - Software must not depends on a RsvdZ bit's ability to retain information when written. - Software must always write 0 to RsvdZ bits when writing one of these register. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 285a21d36524..e2a8671545f2 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -90,6 +90,17 @@ #define MRLSENSOR 0x40000000 #define ATTN_BUTTON 0x80000000 +/* + * Controller SERR-INT Register + */ +#define GLOBAL_INTR_MASK (1 << 0) +#define GLOBAL_SERR_MASK (1 << 1) +#define COMMAND_INTR_MASK (1 << 2) +#define ARBITER_SERR_MASK (1 << 3) +#define COMMAND_DETECTED (1 << 16) +#define ARBITER_DETECTED (1 << 17) +#define SERR_INTR_RSVDZ_MASK 0xfffc0000 + /* * Logical Slot Register definitions */ @@ -1047,7 +1058,8 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Mask Global Interrupt Mask - see implementation note on p. 139 */ /* of SHPC spec rev 1.0*/ temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword |= 0x00000001; + temp_dword |= GLOBAL_INTR_MASK; + temp_dword &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); intr_loc2 = shpc_readl(ctrl, INTR_LOC); @@ -1061,7 +1073,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) * Detect bit in Controller SERR-INT register */ temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword &= 0xfffdffff; + temp_dword &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); @@ -1105,7 +1117,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword &= 0xfffffffe; + temp_dword &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); } @@ -1374,7 +1386,9 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); - tempdword = 0x0003000f; + tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | + COMMAND_INTR_MASK | ARBITER_SERR_MASK); + tempdword &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); @@ -1452,7 +1466,8 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) if (!shpchp_poll_mode) { /* Unmask all general input interrupts and SERR */ tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); - tempdword = 0x0000000a; + tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | + SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); -- cgit v1.2.2 From d49f2c49c39bbd0cb2069fe11c1630c709061037 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 3 May 2006 23:34:17 +0900 Subject: [PATCH] shpchp: Mask Global SERR and Intr at controller release time Global SERR and Interrupt should be masked at shpchp driver unload time. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index e2a8671545f2..8b63f772a6f2 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -798,7 +798,7 @@ static void hpc_release_ctlr(struct controller *ctrl) struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *p, *p_prev; int i; - u32 slot_reg; + u32 slot_reg, serr_int; DBG_ENTER_ROUTINE @@ -822,6 +822,15 @@ static void hpc_release_ctlr(struct controller *ctrl) cleanup_slots(ctrl); + /* + * Mask SERR and System Interrut generation + */ + serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); + serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | + COMMAND_INTR_MASK | ARBITER_SERR_MASK); + serr_int &= ~SERR_INTR_RSVDZ_MASK; + shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); + if (shpchp_poll_mode) { del_timer(&php_ctlr->int_poll_timer); } else { -- cgit v1.2.2 From 82d5f4aaf182c306d2c2ef4d3a89d0fb8e386aa8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 3 May 2006 23:42:04 +0900 Subject: [PATCH] shpchp: Create shpchpd at controller probe time The workqueue thread of shpchp driver should be created only when SHPC based hotplug slots are detected on the system. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_core.c | 8 -------- drivers/pci/hotplug/shpchp_hpc.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 3be4d492ccc2..a14e7de19846 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -491,16 +491,9 @@ static int __init shpcd_init(void) shpchp_poll_mode = 1; #endif - shpchp_wq = create_singlethread_workqueue("shpchpd"); - if (!shpchp_wq) - return -ENOMEM; - retval = pci_register_driver(&shpc_driver); dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - if (retval) { - destroy_workqueue(shpchp_wq); - } return retval; } @@ -508,7 +501,6 @@ static void __exit shpcd_cleanup(void) { dbg("unload_shpchpd()\n"); pci_unregister_driver(&shpc_driver); - destroy_workqueue(shpchp_wq); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 8b63f772a6f2..5e8f589d0b64 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -216,6 +216,8 @@ static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequenc # */ static spinlock_t list_lock; +static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); + static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); @@ -866,6 +868,13 @@ static void hpc_release_ctlr(struct controller *ctrl) kfree(php_ctlr); + /* + * If this is the last controller to be released, destroy the + * shpchpd work queue + */ + if (atomic_dec_and_test(&shpchp_num_controllers)) + destroy_workqueue(shpchp_wq); + DBG_LEAVE_ROUTINE } @@ -1460,6 +1469,16 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctlr_seq_num++; + /* + * If this is the first controller to be initialized, + * initialize the shpchpd work queue + */ + if (atomic_add_return(1, &shpchp_num_controllers) == 1) { + shpchp_wq = create_singlethread_workqueue("shpchpd"); + if (!shpchp_wq) + return -ENOMEM; + } + /* * Unmask all event interrupts of all slots */ -- cgit v1.2.2 From 466ee36b62b4b294ecf68a2eee2e18c6ff8c9be4 Mon Sep 17 00:00:00 2001 From: Mike Habeck Date: Sat, 6 May 2006 09:01:59 -0500 Subject: [PATCH] SGI Hotplug: Incorrect power status This is a repost of a patch submitted by Prarit Bhargava on 01-19-06 that never got integrated. The get_power_status function is currently reporting a bitwise mapping of the slot if the slot is powered on. It should return 1 if powered on and 0 if powered off. Signed-off-by: Mike Habeck Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/sgi_hotplug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index cfee9db52c49..f31d83c2c633 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -461,10 +461,12 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, { struct slot *slot = bss_hotplug_slot->private; struct pcibus_info *pcibus_info; + u32 power; pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); mutex_lock(&sn_hotplug_mutex); - *value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); + power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); + *value = power ? 1 : 0; mutex_unlock(&sn_hotplug_mutex); return 0; } -- cgit v1.2.2 From 56bfada3e1a25c0da6f4590a4b04c67ec10910c2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:22:24 +0900 Subject: [PATCH] pciehp: Replace pci_find_slot() with pci_get_slot() This patch replaces pci_find_slot() with pci_get_slot() in PCIEHP driver. This patch enables PCI Express Hotplug on the system which has multiple PCI domains. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 6aa6a1be4555..922b1831c680 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -204,10 +204,11 @@ int pciehp_configure_device(struct slot *p_slot) struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; int num, fn; - dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); + dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); if (dev) { err("Device %s already exists at %x:%x, cannot hot-add\n", pci_name(dev), p_slot->bus, p_slot->device); + pci_dev_put(dev); return -EINVAL; } @@ -243,18 +244,20 @@ int pciehp_unconfigure_device(struct slot *p_slot) int rc = 0; int j; u8 bctl = 0; + struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(p_slot->bus, + struct pci_dev* temp = pci_get_slot(parent, (p_slot->device << 3) | j); if (!temp) continue; if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { err("Cannot remove display device %s\n", pci_name(temp)); + pci_dev_put(temp); continue; } if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { @@ -262,10 +265,12 @@ int pciehp_unconfigure_device(struct slot *p_slot) if (bctl & PCI_BRIDGE_CTL_VGA) { err("Cannot remove display device %s\n", pci_name(temp)); + pci_dev_put(temp); continue; } } pci_remove_bus_device(temp); + pci_dev_put(temp); } /* * Some PCI Express root ports require fixup after hot-plug operation. -- cgit v1.2.2 From 6e33706b191ff8687f103a86de842b690fd8fb9d Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:23:39 +0900 Subject: [PATCH] pciehp: Add missing pci_dev_put The PCIEHP driver leaks reference counter of pci_dev structures. This patch adds missing pci_dev_put() calls to PCIEHP driver. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 922b1831c680..854aaea09e4d 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -225,6 +225,7 @@ int pciehp_configure_device(struct slot *p_slot) if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { err("Cannot hot-add display device %s\n", pci_name(dev)); + pci_dev_put(dev); continue; } if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || @@ -232,6 +233,7 @@ int pciehp_configure_device(struct slot *p_slot) pciehp_add_bridge(dev); } program_fw_provided_values(dev); + pci_dev_put(dev); } pci_bus_assign_resources(parent); -- cgit v1.2.2 From 132066a9c84af6f5e8d893145a9c63f849143867 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 13:39:45 +0900 Subject: [PATCH] pciehp: Implement get_address callback This patch implements .get_address callback of hotplug_slot_ops for PCIEHP driver. With this patch, we can see bus address of hotplug slots as follows: # cat /sys/bus/pci/slots/0010_0000/address 0000:0a:00 Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 601cf9045b20..c67b7c3f1ddf 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -69,6 +69,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_address (struct hotplug_slot *slot, u32 *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); @@ -81,6 +82,7 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, + .get_address = get_address, .get_max_bus_speed = get_max_bus_speed, .get_cur_bus_speed = get_cur_bus_speed, }; @@ -331,6 +333,18 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } +static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) +{ + struct slot *slot = hotplug_slot->private; + struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; + + return 0; +} + static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = hotplug_slot->private; -- cgit v1.2.2 From d4fbf600666569c3921d12bdcfcfdb2cdb4fd5fb Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:05:59 +0900 Subject: [PATCH] shpchp: Remove unnecessary hpc_ctlr_handle check This patch removes unnecessary error check for hpc_ctlr_handle. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 197 ++++----------------------------------- 1 file changed, 16 insertions(+), 181 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 5e8f589d0b64..5135ceb404d8 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -330,7 +330,6 @@ static inline int shpc_wait_cmd(struct controller *ctrl) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl; u16 cmd_status; int retval = 0; @@ -341,12 +340,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) mutex_lock(&slot->ctrl->cmd_lock); - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - retval = -EINVAL; - goto out; - } - for (i = 0; i < 10; i++) { cmd_status = shpc_readw(ctrl, CMD_STATUS); @@ -401,11 +394,6 @@ static int hpc_check_cmd_status(struct controller *ctrl) int retval = 0; DBG_ENTER_ROUTINE - - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; @@ -442,11 +430,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; @@ -477,11 +460,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; @@ -512,11 +490,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ @@ -532,11 +505,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; *status = (state != 0x3) ? 1 : 0; @@ -550,11 +518,6 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) struct controller *ctrl = slot->ctrl; DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } *prog_int = shpc_readb(ctrl, PROG_INTERFACE); @@ -626,11 +589,6 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - pi = shpc_readb(ctrl, PROG_INTERFACE); sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); @@ -653,11 +611,6 @@ static int hpc_query_power_fault(struct slot * slot) DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); DBG_LEAVE_ROUTINE @@ -667,19 +620,7 @@ static int hpc_query_power_fault(struct slot * slot) static int hpc_set_attention_status(struct slot *slot, u8 value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd = 0; - int rc = 0; - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } switch (value) { case 0 : @@ -695,76 +636,23 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) return -1; } - shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - - return rc; + return shpc_write_cmd(slot, slot->hp_slot, slot_cmd); } static void hpc_set_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - slot_cmd = 0x04; - - shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - - return; + shpc_write_cmd(slot, slot->hp_slot, 0x04); } static void hpc_set_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - slot_cmd = 0x0C; - - shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - - return; + shpc_write_cmd(slot, slot->hp_slot, 0x0c); } static void hpc_set_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - slot_cmd = 0x08; - - shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - - return; + shpc_write_cmd(slot, slot->hp_slot, 0x08); } int shpc_get_ctlr_slot_config(struct controller *ctrl, @@ -778,11 +666,6 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, DBG_ENTER_ROUTINE - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - slot_config = shpc_readl(ctrl, SLOT_CONFIG); *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; *num_ctlr_slots = slot_config & SLOT_NUM; @@ -804,11 +687,6 @@ static void hpc_release_ctlr(struct controller *ctrl) DBG_ENTER_ROUTINE - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - /* * Mask event interrupts and SERRs of all slots */ @@ -881,96 +759,53 @@ DBG_LEAVE_ROUTINE static int hpc_power_on_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - int retval = 0; + int retval; DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - slot_cmd = 0x01; - - retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - + retval = shpc_write_cmd(slot, slot->hp_slot, 0x01); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); - return -1; + return retval; } DBG_LEAVE_ROUTINE - return retval; + return 0; } static int hpc_slot_enable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - int retval = 0; + int retval; DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ - slot_cmd = 0x3A; - - retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - + retval = shpc_write_cmd(slot, slot->hp_slot, 0x3a); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); - return -1; + return retval; } DBG_LEAVE_ROUTINE - return retval; + return 0; } static int hpc_slot_disable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; - int retval = 0; + int retval; DBG_ENTER_ROUTINE - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ - slot_cmd = 0x1F; - - retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - + retval = shpc_write_cmd(slot, slot->hp_slot, 0x1f); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); - return -1; + return retval; } DBG_LEAVE_ROUTINE - return retval; + return 0; } static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) -- cgit v1.2.2 From c4cecc1937cafd8505151452a9f7eea876a5bd9c Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:10:56 +0900 Subject: [PATCH] shpchp: Cleanup interrupt handler This patch cleans up the interrupt handler of shpchp driver. This patch has no functional changes. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 125 ++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 68 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 5135ceb404d8..e0f8c1bbaf12 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -90,6 +90,12 @@ #define MRLSENSOR 0x40000000 #define ATTN_BUTTON 0x80000000 +/* + * Interrupt Locator Register definitions + */ +#define CMD_INTR_PENDING (1 << 0) +#define SLOT_INTR_PENDING(i) (1 << (i + 1)) + /* * Controller SERR-INT Register */ @@ -218,7 +224,7 @@ static spinlock_t list_lock; static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); -static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); +static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); static int hpc_check_cmd_status(struct controller *ctrl); @@ -279,7 +285,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr) } /* Poll for interrupt events. regs == NULL => polling */ - shpc_isr( 0, (void *)php_ctlr, NULL ); + shpc_isr(0, php_ctlr->callback_instance_id, NULL ); init_timer(&php_ctlr->int_poll_timer); if (!shpchp_poll_time) @@ -875,103 +881,86 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) return retval; } -static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) +static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs) { - struct controller *ctrl = NULL; - struct php_ctlr_state_s *php_ctlr; - u8 schedule_flag = 0; - u32 temp_dword, intr_loc, intr_loc2; + struct controller *ctrl = (struct controller *)dev_id; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; + u32 serr_int, slot_reg, intr_loc, intr_loc2; int hp_slot; - if (!dev_id) - return IRQ_NONE; - - if (!shpchp_poll_mode) { - ctrl = (struct controller *)dev_id; - php_ctlr = ctrl->hpc_ctlr_handle; - } else { - php_ctlr = (struct php_ctlr_state_s *) dev_id; - ctrl = (struct controller *)php_ctlr->callback_instance_id; - } - - if (!ctrl) - return IRQ_NONE; - - if (!php_ctlr || !php_ctlr->creg) - return IRQ_NONE; - /* Check to see if it was our interrupt */ intr_loc = shpc_readl(ctrl, INTR_LOC); - if (!intr_loc) return IRQ_NONE; + dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); if(!shpchp_poll_mode) { - /* Mask Global Interrupt Mask - see implementation note on p. 139 */ - /* of SHPC spec rev 1.0*/ - temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword |= GLOBAL_INTR_MASK; - temp_dword &= ~SERR_INTR_RSVDZ_MASK; - shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); + /* + * Mask Global Interrupt Mask - see implementation + * note on p. 139 of SHPC spec rev 1.0 + */ + serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); + serr_int |= GLOBAL_INTR_MASK; + serr_int &= ~SERR_INTR_RSVDZ_MASK; + shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); intr_loc2 = shpc_readl(ctrl, INTR_LOC); dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); } - if (intr_loc & 0x0001) { + if (intr_loc & CMD_INTR_PENDING) { /* * Command Complete Interrupt Pending * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ - temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword &= ~SERR_INTR_RSVDZ_MASK; - shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); + serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); + serr_int &= ~SERR_INTR_RSVDZ_MASK; + shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); + ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } - if ((intr_loc = (intr_loc >> 1)) == 0) + if (!(intr_loc & ~CMD_INTR_PENDING)) goto out; for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { - /* To find out which slot has interrupt pending */ - if ((intr_loc >> hp_slot) & 0x01) { - temp_dword = shpc_readl(ctrl, SLOT_REG(hp_slot)); - dbg("%s: Slot %x with intr, slot register = %x\n", - __FUNCTION__, hp_slot, temp_dword); - if ((php_ctlr->switch_change_callback) && - (temp_dword & MRL_CHANGE_DETECTED)) - schedule_flag += php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && - (temp_dword & BUTTON_PRESS_DETECTED)) - schedule_flag += php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && - (temp_dword & PRSNT_CHANGE_DETECTED)) - schedule_flag += php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && - (temp_dword & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))) - schedule_flag += php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); - - /* Clear all slot events */ - temp_dword &= ~SLOT_REG_RSVDZ_MASK; - shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); - - intr_loc2 = shpc_readl(ctrl, INTR_LOC); - dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); - } + /* To find out which slot has interrupt pending */ + if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) + continue; + + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); + dbg("%s: Slot %x with intr, slot register = %x\n", + __FUNCTION__, hp_slot, slot_reg); + + if (slot_reg & MRL_CHANGE_DETECTED) + php_ctlr->switch_change_callback( + hp_slot, php_ctlr->callback_instance_id); + + if (slot_reg & BUTTON_PRESS_DETECTED) + php_ctlr->attention_button_callback( + hp_slot, php_ctlr->callback_instance_id); + + if (slot_reg & PRSNT_CHANGE_DETECTED) + php_ctlr->presence_change_callback( + hp_slot , php_ctlr->callback_instance_id); + + if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) + php_ctlr->power_fault_callback( + hp_slot, php_ctlr->callback_instance_id); + + /* Clear all slot events */ + slot_reg &= ~SLOT_REG_RSVDZ_MASK; + shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } out: if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ - temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); - temp_dword &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); - shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); + serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); + serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); + shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); } return IRQ_HANDLED; -- cgit v1.2.2 From 4085399da3c2176ba8ed64e93a2722907d41df3f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:11:48 +0900 Subject: [PATCH] shpchp: Cleanup SHPC commands This patch cleans up the code related to issuing SHPC commands. This patch has no functional changes. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 98 ++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 50 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index e0f8c1bbaf12..f6b3bf3ee7ca 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -147,39 +147,37 @@ #define CON_PFAULT_SERR_MASK (1 << 30) #define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) -/* SHPC 'write' operations/commands */ - -/* Slot operation - 0x00h to 0x3Fh */ - -#define NO_CHANGE 0x00 - -/* Slot state - Bits 0 & 1 of controller command register */ -#define SET_SLOT_PWR 0x01 -#define SET_SLOT_ENABLE 0x02 -#define SET_SLOT_DISABLE 0x03 - -/* Power indicator state - Bits 2 & 3 of controller command register*/ -#define SET_PWR_ON 0x04 -#define SET_PWR_BLINK 0x08 -#define SET_PWR_OFF 0x0C - -/* Attention indicator state - Bits 4 & 5 of controller command register*/ -#define SET_ATTN_ON 0x010 -#define SET_ATTN_BLINK 0x020 -#define SET_ATTN_OFF 0x030 - -/* Set bus speed/mode A - 0x40h to 0x47h */ -#define SETA_PCI_33MHZ 0x40 +/* + * SHPC Command Code definitnions + * + * Slot Operation 00h - 3Fh + * Set Bus Segment Speed/Mode A 40h - 47h + * Power-Only All Slots 48h + * Enable All Slots 49h + * Set Bus Segment Speed/Mode B (PI=2) 50h - 5Fh + * Reserved Command Codes 60h - BFh + * Vendor Specific Commands C0h - FFh + */ +#define SET_SLOT_PWR 0x01 /* Slot Operation */ +#define SET_SLOT_ENABLE 0x02 +#define SET_SLOT_DISABLE 0x03 +#define SET_PWR_ON 0x04 +#define SET_PWR_BLINK 0x08 +#define SET_PWR_OFF 0x0c +#define SET_ATTN_ON 0x10 +#define SET_ATTN_BLINK 0x20 +#define SET_ATTN_OFF 0x30 +#define SETA_PCI_33MHZ 0x40 /* Set Bus Segment Speed/Mode A */ #define SETA_PCI_66MHZ 0x41 #define SETA_PCIX_66MHZ 0x42 #define SETA_PCIX_100MHZ 0x43 #define SETA_PCIX_133MHZ 0x44 -#define RESERV_1 0x45 -#define RESERV_2 0x46 -#define RESERV_3 0x47 - -/* Set bus speed/mode B - 0x50h to 0x5fh */ -#define SETB_PCI_33MHZ 0x50 +#define SETA_RESERVED1 0x45 +#define SETA_RESERVED2 0x46 +#define SETA_RESERVED3 0x47 +#define SET_PWR_ONLY_ALL 0x48 /* Power-Only All Slots */ +#define SET_ENABLE_ALL 0x49 /* Enable All Slots */ +#define SETB_PCI_33MHZ 0x50 /* Set Bus Segment Speed/Mode B */ #define SETB_PCI_66MHZ 0x51 #define SETB_PCIX_66MHZ_PM 0x52 #define SETB_PCIX_100MHZ_PM 0x53 @@ -193,23 +191,21 @@ #define SETB_PCIX_66MHZ_533 0x5b #define SETB_PCIX_100MHZ_533 0x5c #define SETB_PCIX_133MHZ_533 0x5d +#define SETB_RESERVED1 0x5e +#define SETB_RESERVED2 0x5f - -/* Power-on all slots - 0x48h */ -#define SET_PWR_ON_ALL 0x48 - -/* Enable all slots - 0x49h */ -#define SET_ENABLE_ALL 0x49 - -/* SHPC controller command error code */ +/* + * SHPC controller command error code + */ #define SWITCH_OPEN 0x1 #define INVALID_CMD 0x2 #define INVALID_SPEED_MODE 0x4 -/* For accessing SHPC Working Register Set */ +/* + * For accessing SHPC Working Register Set via PCI Configuration Space + */ #define DWORD_SELECT 0x2 #define DWORD_DATA 0x4 -#define BASE_OFFSET 0x0 /* Field Offset in Logical Slot Register - byte boundary */ #define SLOT_EVENT_LATCH 0x2 @@ -630,13 +626,13 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) switch (value) { case 0 : - slot_cmd = 0x30; /* OFF */ + slot_cmd = SET_ATTN_OFF; /* OFF */ break; case 1: - slot_cmd = 0x10; /* ON */ + slot_cmd = SET_ATTN_ON; /* ON */ break; case 2: - slot_cmd = 0x20; /* BLINK */ + slot_cmd = SET_ATTN_BLINK; /* BLINK */ break; default: return -1; @@ -648,17 +644,17 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) static void hpc_set_green_led_on(struct slot *slot) { - shpc_write_cmd(slot, slot->hp_slot, 0x04); + shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON); } static void hpc_set_green_led_off(struct slot *slot) { - shpc_write_cmd(slot, slot->hp_slot, 0x0c); + shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF); } static void hpc_set_green_led_blink(struct slot *slot) { - shpc_write_cmd(slot, slot->hp_slot, 0x08); + shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK); } int shpc_get_ctlr_slot_config(struct controller *ctrl, @@ -769,7 +765,7 @@ static int hpc_power_on_slot(struct slot * slot) DBG_ENTER_ROUTINE - retval = shpc_write_cmd(slot, slot->hp_slot, 0x01); + retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); return retval; @@ -786,8 +782,9 @@ static int hpc_slot_enable(struct slot * slot) DBG_ENTER_ROUTINE - /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ - retval = shpc_write_cmd(slot, slot->hp_slot, 0x3a); + /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ + retval = shpc_write_cmd(slot, slot->hp_slot, + SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); return retval; @@ -803,8 +800,9 @@ static int hpc_slot_disable(struct slot * slot) DBG_ENTER_ROUTINE - /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ - retval = shpc_write_cmd(slot, slot->hp_slot, 0x1f); + /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ + retval = shpc_write_cmd(slot, slot->hp_slot, + SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); return retval; -- cgit v1.2.2 From f42639572680f4d69d9522f91c65e793ebeca098 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:13:02 +0900 Subject: [PATCH] shpchp: Cleanup interrupt polling timer This patch cleans up the interrupt polling timer code in shpchp_hpc.c. This has no functional changes. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 59 ++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 33 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index f6b3bf3ee7ca..3a8186c405f1 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -221,8 +221,7 @@ static spinlock_t list_lock; static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); - -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec); static int hpc_check_cmd_status(struct controller *ctrl); static inline u8 shpc_readb(struct controller *ctrl, int reg) @@ -268,47 +267,41 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index, return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); } -/* This is the interrupt polling timeout function. */ +/* + * This is the interrupt polling timeout function. + */ static void int_poll_timeout(unsigned long lphp_ctlr) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; - - DBG_ENTER_ROUTINE + struct php_ctlr_state_s *php_ctlr = + (struct php_ctlr_state_s *)lphp_ctlr; - if ( !php_ctlr ) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } + DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ - shpc_isr(0, php_ctlr->callback_instance_id, NULL ); + /* Poll for interrupt events. regs == NULL => polling */ + shpc_isr(0, php_ctlr->callback_instance_id, NULL); - init_timer(&php_ctlr->int_poll_timer); + init_timer(&php_ctlr->int_poll_timer); if (!shpchp_poll_time) - shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + shpchp_poll_time = 2; /* default polling interval is 2 sec */ - start_int_poll_timer(php_ctlr, shpchp_poll_time); - - return; + start_int_poll_timer(php_ctlr, shpchp_poll_time); + + DBG_LEAVE_ROUTINE } -/* This function starts the interrupt polling timer. */ -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +/* + * This function starts the interrupt polling timer. + */ +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) { - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } - - if ( ( seconds <= 0 ) || ( seconds > 60 ) ) - seconds = 2; /* Clamp to sane value */ - - php_ctlr->int_poll_timer.function = &int_poll_timeout; - php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ - php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; - add_timer(&php_ctlr->int_poll_timer); - - return; + /* Clamp to sane value */ + if ((sec <= 0) || (sec > 60)) + sec = 2; + + php_ctlr->int_poll_timer.function = &int_poll_timeout; + php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; + php_ctlr->int_poll_timer.expires = jiffies + sec * HZ; + add_timer(&php_ctlr->int_poll_timer); } static inline int shpc_wait_cmd(struct controller *ctrl) -- cgit v1.2.2 From ea83bc1dabdca9da643972b591259a7657459ff5 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:12:23 +0900 Subject: [PATCH] shpchp: Remove Unused hpc_evelnt_lock This patch removes unused hpc_event_lock. This patch has no functional change. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 3a8186c405f1..45facaad39bd 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -211,8 +211,6 @@ #define SLOT_EVENT_LATCH 0x2 #define SLOT_SERR_INT_MASK 0x3 -static spinlock_t hpc_event_lock; - DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequenc # */ @@ -1105,7 +1103,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) void *instance_id = ctrl; int rc, num_slots = 0; u8 hp_slot; - static int first = 1; u32 shpc_base_offset; u32 tempdword, slot_reg, slot_config; u8 i; @@ -1167,11 +1164,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctrl->mmio_size = 0x24 + 0x4 * num_slots; } - if (first) { - spin_lock_init(&hpc_event_lock); - first = 0; - } - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); -- cgit v1.2.2 From 99ff124d1673a1e3f19061ebc82634608d1119ed Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 12 May 2006 11:13:50 +0900 Subject: [PATCH] shpchp: Cleanup improper info messages Current SHPCHP driver shows device number of slots in info messages, but it is useless and should be replaced with slot name. This patch replaces the device number shown in the info messages with the slot name. Signed-off-by: Kenji Kaneshige Cc: Kristen Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp.h | 6 +++--- drivers/pci/hotplug/shpchp_ctrl.c | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index b70fddbce934..7208b95c6ee7 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -168,9 +168,9 @@ struct controller { * error Messages */ #define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%d - powering on due to button press.\n" -#define msg_button_off "PCI slot #%d - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_on "PCI slot #%s - powering on due to button press.\n" +#define msg_button_off "PCI slot #%s - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" /* sysfs functions for the hotplug controller info */ extern void shpchp_create_ctrl_files (struct controller *ctrl); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 4e6381481c55..c39901dbff20 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -72,7 +72,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Button pressed on Slot(%s)\n", p_slot->name); event_type = INT_BUTTON_PRESS; queue_interrupt_event(p_slot, event_type); @@ -101,7 +101,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) /* * Switch opened */ - info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch open on Slot(%s)\n", p_slot->name); event_type = INT_SWITCH_OPEN; if (p_slot->pwr_save && p_slot->presence_save) { event_type = INT_POWER_FAULT; @@ -111,7 +111,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) /* * Switch closed */ - info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Latch close on Slot(%s)\n", p_slot->name); event_type = INT_SWITCH_CLOSE; } @@ -139,13 +139,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) /* * Card Present */ - info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card present on Slot(%s)\n", p_slot->name); event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Card not present on Slot(%s)\n", p_slot->name); event_type = INT_PRESENCE_OFF; } @@ -169,14 +169,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) /* * Power fault Cleared */ - info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault cleared on Slot(%s)\n", p_slot->name); p_slot->status = 0x00; event_type = INT_POWER_FAULT_CLEAR; } else { /* * Power fault */ - info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); + info("Power fault on Slot(%s)\n", p_slot->name); event_type = INT_POWER_FAULT; /* set power fault status for this board */ p_slot->status = 0xFF; @@ -496,10 +496,10 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); + info(msg_button_off, p_slot->name); } else { p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); + info(msg_button_on, p_slot->name); } /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); @@ -522,7 +522,7 @@ static void handle_button_press_event(struct slot *p_slot) else p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); - info(msg_button_cancel, p_slot->number); + info(msg_button_cancel, p_slot->name); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -575,17 +575,17 @@ static int shpchp_enable_slot (struct slot *p_slot) mutex_lock(&p_slot->ctrl->crit_sect); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("No adapter on slot(%s)\n", p_slot->name); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("Latch open on slot(%s)\n", p_slot->name); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + info("Already enabled on slot(%s)\n", p_slot->name); goto out; } @@ -634,17 +634,17 @@ static int shpchp_disable_slot (struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + info("No adapter on slot(%s)\n", p_slot->name); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + info("Latch open on slot(%s)\n", p_slot->name); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + info("Already disabled slot(%s)\n", p_slot->name); goto out; } -- cgit v1.2.2 From 9df7fde52c33075b9f9148ee31215c03824fcc38 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Thu, 1 Jun 2006 11:41:44 +0200 Subject: [PATCH] PCI Hotplug: fake NULL pointer dereferences in IBM Hot Plug Controller Driver Remove checks for value, since the hotplug core always provides a valid value. Signed-off-by: Eric Sesterhenn Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/ibmphp_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index e13d5b87241a..59392946c2bd 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -285,7 +285,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { memcpy(&myslot, pslot, sizeof(struct slot)); @@ -315,7 +315,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { memcpy(&myslot, pslot, sizeof(struct slot)); @@ -342,7 +342,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { memcpy(&myslot, pslot, sizeof(struct slot)); @@ -369,7 +369,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { memcpy(&myslot, pslot, sizeof(struct slot)); @@ -401,7 +401,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { rc = 0; @@ -441,7 +441,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe ibmphp_lock_operations(); - if (hotplug_slot && value) { + if (hotplug_slot) { pslot = hotplug_slot->private; if (pslot) { rc = get_cur_bus_info(&pslot); -- cgit v1.2.2 From 9c64f9774805ba5d5ad4129899bdd822f61874e9 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 9 May 2006 00:50:31 -0700 Subject: [PATCH] PCI Hotplug: Fix recovery path from errors during pcie_init() Signed-off-by: Jan Beulich Cc: Kristen Accardi Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 081dfef4fe62..d77138ecb098 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1471,7 +1471,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort_free_irq; } intr_enable = intr_enable | PRSN_DETECT_ENABLE; @@ -1497,19 +1497,19 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort_free_irq; } rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort_disable_intr; } temp_word = 0x1F; /* Clear all events */ rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort_disable_intr; } if (pciehp_force) { @@ -1518,7 +1518,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) } else { rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); if (rc) - goto abort_free_ctlr; + goto abort_disable_intr; } /* Add this HPC instance into the HPC list */ @@ -1545,6 +1545,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) return 0; /* We end up here for the many possible ways to fail this API. */ +abort_disable_intr: + rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + if (!rc) { + temp_word &= ~(intr_enable | HP_INTR_ENABLE); + rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + } + if (rc) + err("%s : disabling interrupts failed\n", __FUNCTION__); + +abort_free_irq: + if (pciehp_poll_mode) + del_timer_sync(&php_ctlr->int_poll_timer); + else + free_irq(php_ctlr->irq, ctrl); + abort_free_ctlr: pcie_cap_base = saved_cap_base; kfree(php_ctlr); -- cgit v1.2.2 From fd58e55fcf5568e51da2ed54d7acd049c3fdb184 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 10 Apr 2006 21:17:48 -0500 Subject: [PATCH] PCI: msi abstractions and support for altix Abstract portions of the MSI core for platforms that do not use standard APIC interrupt controllers. This is implemented through a new arch-specific msi setup routine, and a set of msi ops which can be set on a per platform basis. Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- drivers/pci/Makefile | 6 +- drivers/pci/msi-altix.c | 18 ++++ drivers/pci/msi-apic.c | 100 +++++++++++++++++++++++ drivers/pci/msi.c | 212 ++++++++++++++++++++++++++++++------------------ drivers/pci/msi.h | 133 ++++++++++++++++-------------- 5 files changed, 325 insertions(+), 144 deletions(-) create mode 100644 drivers/pci/msi-altix.c create mode 100644 drivers/pci/msi-apic.c (limited to 'drivers/pci') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o -obj-$(CONFIG_PCI_MSI) += msi.o + +msiobj-y := msi.o msi-apic.o +msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o +msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o +obj-$(CONFIG_PCI_MSI) += $(msiobj-y) # # ACPI Related PCI FW Functions diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..9bd240602c1e --- /dev/null +++ b/drivers/pci/msi-altix.c @@ -0,0 +1,18 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include + +int +sn_msi_init(void) +{ + /* + * return error until MSI is supported on altix platforms + */ + return -EINVAL; +} diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c @@ -0,0 +1,100 @@ +/* + * MSI hooks for standard x86 apic + */ + +#include +#include + +#include "msi.h" + +/* + * Shifts for APIC-based data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) + +#define MSI_DATA_DELIVERY_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for APIC-based bus address + */ + +#define MSI_ADDR_HEADER 0xfee00000 + +#define MSI_ADDR_DESTID_MASK 0xfff0000f +#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) + +#define MSI_ADDR_DESTMODE_SHIFT 2 +#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) +#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) + + +static void +msi_target_apic(unsigned int vector, + unsigned int dest_cpu, + u32 *address_hi, /* in/out */ + u32 *address_lo) /* in/out */ +{ + u32 addr = *address_lo; + + addr &= MSI_ADDR_DESTID_MASK; + addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); + + *address_lo = addr; +} + +static int +msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ + unsigned int vector, + u32 *address_hi, + u32 *address_lo, + u32 *data) +{ + unsigned long dest_phys_id; + + dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); + + *address_hi = 0; + *address_lo = MSI_ADDR_HEADER | + MSI_ADDR_DESTMODE_PHYS | + MSI_ADDR_REDIRECTION_CPU | + MSI_ADDR_DESTID_CPU(dest_phys_id); + + *data = MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + MSI_DATA_DELIVERY_FIXED | + MSI_DATA_VECTOR(vector); + + return 0; +} + +static void +msi_teardown_apic(unsigned int vector) +{ + return; /* no-op */ +} + +/* + * Generic ops used on most IA archs/platforms. Set with msi_register() + */ + +struct msi_ops msi_apic_ops = { + .setup = msi_setup_apic, + .teardown = msi_teardown_apic, + .target = msi_target_apic, +}; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..55ff52df5fe7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -23,8 +23,6 @@ #include "pci.h" #include "msi.h" -#define MSI_TARGET_CPU first_cpu(cpu_online_map) - static DEFINE_SPINLOCK(msi_lock); static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; @@ -40,6 +38,15 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; #endif +static struct msi_ops *msi_ops; + +int +msi_register(struct msi_ops *ops) +{ + msi_ops = ops; + return 0; +} + static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) { memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); @@ -92,7 +99,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) { struct msi_desc *entry; - struct msg_address address; + u32 address_hi, address_lo; unsigned int irq = vector; unsigned int dest_cpu = first_cpu(cpu_mask); @@ -108,28 +115,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) if (!pos) return; + pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), + &address_hi); pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), - &address.lo_address.value); - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= (cpu_physical_id(dest_cpu) << - MSI_TARGET_CPU_SHIFT); - entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); + &address_lo); + + msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); + + pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), + address_hi); pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), - address.lo_address.value); + address_lo); set_native_irq_info(irq, cpu_mask); break; } case PCI_CAP_ID_MSIX: { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; - - address.lo_address.value = readl(entry->mask_base + offset); - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= (cpu_physical_id(dest_cpu) << - MSI_TARGET_CPU_SHIFT); - entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); - writel(address.lo_address.value, entry->mask_base + offset); + int offset_hi = + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; + int offset_lo = + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; + + address_hi = readl(entry->mask_base + offset_hi); + address_lo = readl(entry->mask_base + offset_lo); + + msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); + + writel(address_hi, entry->mask_base + offset_hi); + writel(address_lo, entry->mask_base + offset_lo); set_native_irq_info(irq, cpu_mask); break; } @@ -251,30 +266,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .set_affinity = set_msi_affinity }; -static void msi_data_init(struct msg_data *msi_data, - unsigned int vector) -{ - memset(msi_data, 0, sizeof(struct msg_data)); - msi_data->vector = (u8)vector; - msi_data->delivery_mode = MSI_DELIVERY_MODE; - msi_data->level = MSI_LEVEL_MODE; - msi_data->trigger = MSI_TRIGGER_MODE; -} - -static void msi_address_init(struct msg_address *msi_address) -{ - unsigned int dest_id; - unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); - - memset(msi_address, 0, sizeof(struct msg_address)); - msi_address->hi_address = (u32)0; - dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); - msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; - msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; - msi_address->lo_address.u.dest_id = dest_id; - msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); -} - static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); static int assign_msi_vector(void) { @@ -369,13 +360,29 @@ static int msi_init(void) return status; } + status = msi_arch_init(); + if (status < 0) { + pci_msi_enable = 0; + printk(KERN_WARNING + "PCI: MSI arch init failed. MSI disabled.\n"); + return status; + } + + if (! msi_ops) { + printk(KERN_WARNING + "PCI: MSI ops not registered. MSI disabled.\n"); + status = -EINVAL; + return status; + } + + last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: MSI cache init failed\n"); return status; } - last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); + if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); @@ -575,6 +582,8 @@ void pci_restore_msi_state(struct pci_dev *dev) int pci_save_msix_state(struct pci_dev *dev) { int pos; + int temp; + int vector, head, tail = 0; u16 control; struct pci_cap_saved_state *save_state; @@ -582,6 +591,7 @@ int pci_save_msix_state(struct pci_dev *dev) if (pos <= 0 || dev->no_msi) return 0; + /* save the capability */ pci_read_config_word(dev, msi_control_reg(pos), &control); if (!(control & PCI_MSIX_FLAGS_ENABLE)) return 0; @@ -593,6 +603,38 @@ int pci_save_msix_state(struct pci_dev *dev) } *((u16 *)&save_state->data[0]) = control; + /* save the table */ + temp = dev->irq; + if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { + kfree(save_state); + return -EINVAL; + } + + vector = head = dev->irq; + while (head != tail) { + int j; + void __iomem *base; + struct msi_desc *entry; + + entry = msi_desc[vector]; + base = entry->mask_base; + j = entry->msi_attrib.entry_nr; + + entry->address_lo_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + entry->address_hi_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + entry->data_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_DATA_OFFSET); + + tail = msi_desc[vector]->link.tail; + vector = tail; + } + dev->irq = temp; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); @@ -606,8 +648,6 @@ void pci_restore_msix_state(struct pci_dev *dev) int vector, head, tail = 0; void __iomem *base; int j; - struct msg_address address; - struct msg_data data; struct msi_desc *entry; int temp; struct pci_cap_saved_state *save_state; @@ -633,20 +673,13 @@ void pci_restore_msix_state(struct pci_dev *dev) base = entry->mask_base; j = entry->msi_attrib.entry_nr; - msi_address_init(&address); - msi_data_init(&data, vector); - - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= entry->msi_attrib.current_cpu << - MSI_TARGET_CPU_SHIFT; - - writel(address.lo_address.value, + writel(entry->address_lo_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(address.hi_address, + writel(entry->address_hi_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(*(u32*)&data, + writel(entry->data_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_DATA_OFFSET); @@ -660,30 +693,32 @@ void pci_restore_msix_state(struct pci_dev *dev) } #endif -static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) { - struct msg_address address; - struct msg_data data; + int status; + u32 address_hi; + u32 address_lo; + u32 data; int pos, vector = dev->irq; u16 control; pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); + /* Configure MSI capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - pci_write_config_dword(dev, msi_lower_address_reg(pos), - address.lo_address.value); + status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); + if (status < 0) + return status; + + pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); if (is_64bit_address(control)) { pci_write_config_dword(dev, - msi_upper_address_reg(pos), address.hi_address); + msi_upper_address_reg(pos), address_hi); pci_write_config_word(dev, - msi_data_reg(pos, 1), *((u32*)&data)); + msi_data_reg(pos, 1), data); } else pci_write_config_word(dev, - msi_data_reg(pos, 0), *((u32*)&data)); + msi_data_reg(pos, 0), data); if (entry->msi_attrib.maskbit) { unsigned int maskbits, temp; /* All MSIs are unmasked by default, Mask them all */ @@ -697,6 +732,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); } + + return 0; } /** @@ -710,6 +747,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) **/ static int msi_capability_init(struct pci_dev *dev) { + int status; struct msi_desc *entry; int pos, vector; u16 control; @@ -742,7 +780,12 @@ static int msi_capability_init(struct pci_dev *dev) /* Replace with MSI handler */ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ - msi_register_init(dev, entry); + status = msi_register_init(dev, entry); + if (status != 0) { + dev->irq = entry->msi_attrib.default_vector; + kmem_cache_free(msi_cachep, entry); + return status; + } attach_msi_entry(entry, vector); /* Set MSI enabled bits */ @@ -765,8 +808,10 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - struct msg_address address; - struct msg_data data; + u32 address_hi; + u32 address_lo; + u32 data; + int status; int vector, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; @@ -822,18 +867,20 @@ static int msix_capability_init(struct pci_dev *dev, /* Replace with MSI-X handler */ irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); /* Configure MSI-X capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = - ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - writel(address.lo_address.value, + status = msi_ops->setup(dev, vector, + &address_hi, + &address_lo, + &data); + if (status < 0) + break; + + writel(address_lo, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(address.hi_address, + writel(address_hi, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(*(u32*)&data, + writel(data, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_DATA_OFFSET); attach_msi_entry(entry, vector); @@ -901,9 +948,10 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); - msi_register_init(dev, msi_desc[dev->irq]); - enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); - return 0; + status = msi_register_init(dev, msi_desc[dev->irq]); + if (status == 0) + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + return status; } spin_unlock_irqrestore(&msi_lock, flags); dev->irq = temp; @@ -980,6 +1028,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) void __iomem *base; unsigned long flags; + msi_ops->teardown(vector); + spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[vector]; if (!entry || entry->dev != dev) { diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,6 +6,68 @@ #ifndef MSI_H #define MSI_H +/* + * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) + * to abstract platform-specific tasks relating to MSI address generation + * and resource management. + */ +struct msi_ops { + /** + * setup - generate an MSI bus address and data for a given vector + * @pdev: PCI device context (in) + * @vector: vector allocated by the msi core (in) + * @addr_hi: upper 32 bits of PCI bus MSI address (out) + * @addr_lo: lower 32 bits of PCI bus MSI address (out) + * @data: MSI data payload (out) + * + * Description: The setup op is used to generate a PCI bus addres and + * data which the msi core will program into the card MSI capability + * registers. The setup routine is responsible for picking an initial + * cpu to target the MSI at. The setup routine is responsible for + * examining pdev to determine the MSI capabilities of the card and + * generating a suitable address/data. The setup routine is + * responsible for allocating and tracking any system resources it + * needs to route the MSI to the cpu it picks, and for associating + * those resources with the passed in vector. + * + * Returns 0 if the MSI address/data was successfully setup. + **/ + + int (*setup) (struct pci_dev *pdev, unsigned int vector, + u32 *addr_hi, u32 *addr_lo, u32 *data); + + /** + * teardown - release resources allocated by setup + * @vector: vector context for resources (in) + * + * Description: The teardown op is used to release any resources + * that were allocated in the setup routine associated with the passed + * in vector. + **/ + + void (*teardown) (unsigned int vector); + + /** + * target - retarget an MSI at a different cpu + * @vector: vector context for resources (in) + * @cpu: new cpu to direct vector at (in) + * @addr_hi: new value of PCI bus upper 32 bits (in/out) + * @addr_lo: new value of PCI bus lower 32 bits (in/out) + * + * Description: The target op is used to redirect an MSI vector + * at a different cpu. addr_hi/addr_lo coming in are the existing + * values that the MSI core has programmed into the card. The + * target code is responsible for freeing any resources (if any) + * associated with the old address, and generating a new PCI bus + * addr_hi/addr_lo that will redirect the vector at the indicated cpu. + **/ + + void (*target) (unsigned int vector, unsigned int cpu, + u32 *addr_hi, u32 *addr_lo); +}; + +extern int msi_register(struct msi_ops *ops); + #include /* @@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) -/* - * MSI Defined Data Structures - */ -#define MSI_ADDRESS_HEADER 0xfee -#define MSI_ADDRESS_HEADER_SHIFT 12 -#define MSI_ADDRESS_HEADER_MASK 0xfff000 -#define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f -#define MSI_TARGET_CPU_MASK 0xff -#define MSI_DELIVERY_MODE 0 -#define MSI_LEVEL_MODE 1 /* Edge always assert */ -#define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ -#define MSI_PHYSICAL_MODE 0 -#define MSI_LOGICAL_MODE 1 -#define MSI_REDIRECTION_HINT_MODE 0 - -struct msg_data { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u32 vector : 8; - __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ - __u32 reserved_1 : 3; - __u32 level : 1; /* 0: deassert | 1: assert */ - __u32 trigger : 1; /* 0: edge | 1: level */ - __u32 reserved_2 : 16; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u32 reserved_2 : 16; - __u32 trigger : 1; /* 0: edge | 1: level */ - __u32 level : 1; /* 0: deassert | 1: assert */ - __u32 reserved_1 : 3; - __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ - __u32 vector : 8; -#else -#error "Bitfield endianness not defined! Check your byteorder.h" -#endif -} __attribute__ ((packed)); - -struct msg_address { - union { - struct { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u32 reserved_1 : 2; - __u32 dest_mode : 1; /*0:physic | 1:logic */ - __u32 redirection_hint: 1; /*0: dedicated CPU - 1: lowest priority */ - __u32 reserved_2 : 4; - __u32 dest_id : 24; /* Destination ID */ -#elif defined(__BIG_ENDIAN_BITFIELD) - __u32 dest_id : 24; /* Destination ID */ - __u32 reserved_2 : 4; - __u32 redirection_hint: 1; /*0: dedicated CPU - 1: lowest priority */ - __u32 dest_mode : 1; /*0:physic | 1:logic */ - __u32 reserved_1 : 2; -#else -#error "Bitfield endianness not defined! Check your byteorder.h" -#endif - }u; - __u32 value; - }lo_address; - __u32 hi_address; -} __attribute__ ((packed)); - struct msi_desc { struct { __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ @@ -132,7 +133,7 @@ struct msi_desc { __u8 reserved: 1; /* reserved */ __u8 entry_nr; /* specific enabled entry */ __u8 default_vector; /* default pre-assigned vector */ - __u8 current_cpu; /* current destination cpu */ + __u8 unused; /* formerly unused destination cpu*/ }msi_attrib; struct { @@ -142,6 +143,14 @@ struct msi_desc { void __iomem *mask_base; struct pci_dev *dev; + +#ifdef CONFIG_PM + /* PM save area for MSIX address/data */ + + u32 address_hi_save; + u32 address_lo_save; + u32 data_save; +#endif }; #endif /* MSI_H */ -- cgit v1.2.2 From 10083072bfabc40bc47306e512c158c57cf55c2e Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Fri, 14 Apr 2006 16:03:49 -0500 Subject: [PATCH] PCI: per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions Abstract IA64_FIRST_DEVICE_VECTOR/IA64_LAST_DEVICE_VECTOR since SN platforms use a subset of the IA64 range. Implement this by making the above macros global variables which the platform can override in it setup code. Also add a reserve_irq_vector() routine used by SN to mark a vector's as in-use when that weren't allocated through assign_irq_vector(). Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 55ff52df5fe7..f8105783da2f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -35,7 +35,7 @@ static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; +u8 irq_vector[NR_IRQ_VECTORS]; #endif static struct msi_ops *msi_ops; @@ -383,6 +383,10 @@ static int msi_init(void) return status; } +#ifndef CONFIG_X86_IO_APIC + irq_vector[0] = FIRST_DEVICE_VECTOR; +#endif + if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); -- cgit v1.2.2 From 83821d3f558dc651e555d62182ed0c95651f41a6 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Fri, 14 Apr 2006 16:03:54 -0500 Subject: [PATCH] PCI: altix: msi support MSI callouts for altix. Involves a fair amount of code reorg in sn irq.c code as well as adding some extensions to the altix PCI provider abstaction. Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi-altix.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index 9bd240602c1e..bed4183a5e39 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c @@ -6,13 +6,205 @@ * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. */ -#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "msi.h" + +struct sn_msi_info { + u64 pci_addr; + struct sn_irq_info *sn_irq_info; +}; + +static struct sn_msi_info *sn_msi_info; + +static void +sn_msi_teardown(unsigned int vector) +{ + nasid_t nasid; + int widget; + struct pci_dev *pdev; + struct pcidev_info *sn_pdev; + struct sn_irq_info *sn_irq_info; + struct pcibus_bussoft *bussoft; + struct sn_pcibus_provider *provider; + + sn_irq_info = sn_msi_info[vector].sn_irq_info; + if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) + return; + + sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; + pdev = sn_pdev->pdi_linux_pcidev; + provider = SN_PCIDEV_BUSPROVIDER(pdev); + + (*provider->dma_unmap)(pdev, + sn_msi_info[vector].pci_addr, + PCI_DMA_FROMDEVICE); + sn_msi_info[vector].pci_addr = 0; + + bussoft = SN_PCIDEV_BUSSOFT(pdev); + nasid = NASID_GET(bussoft->bs_base); + widget = (nasid & 1) ? + TIO_SWIN_WIDGETNUM(bussoft->bs_base) : + SWIN_WIDGETNUM(bussoft->bs_base); + + sn_intr_free(nasid, widget, sn_irq_info); + sn_msi_info[vector].sn_irq_info = NULL; + + return; +} int -sn_msi_init(void) +sn_msi_setup(struct pci_dev *pdev, unsigned int vector, + u32 *addr_hi, u32 *addr_lo, u32 *data) { + int widget; + int status; + nasid_t nasid; + u64 bus_addr; + struct sn_irq_info *sn_irq_info; + struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); + + if (bussoft == NULL) + return -EINVAL; + + if (provider == NULL || provider->dma_map_consistent == NULL) + return -EINVAL; + + /* + * Set up the vector plumbing. Let the prom (via sn_intr_alloc) + * decide which cpu to direct this msi at by default. + */ + + nasid = NASID_GET(bussoft->bs_base); + widget = (nasid & 1) ? + TIO_SWIN_WIDGETNUM(bussoft->bs_base) : + SWIN_WIDGETNUM(bussoft->bs_base); + + sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (! sn_irq_info) + return -ENOMEM; + + status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); + if (status) { + kfree(sn_irq_info); + return -ENOMEM; + } + + sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ + sn_irq_fixup(pdev, sn_irq_info); + + /* Prom probably should fill these in, but doesn't ... */ + sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; + sn_irq_info->irq_bridge = (void *)bussoft->bs_base; + /* - * return error until MSI is supported on altix platforms + * Map the xio address into bus space */ - return -EINVAL; + bus_addr = (*provider->dma_map_consistent)(pdev, + sn_irq_info->irq_xtalkaddr, + sizeof(sn_irq_info->irq_xtalkaddr), + SN_DMA_MSI|SN_DMA_ADDR_XIO); + if (! bus_addr) { + sn_intr_free(nasid, widget, sn_irq_info); + kfree(sn_irq_info); + return -ENOMEM; + } + + sn_msi_info[vector].sn_irq_info = sn_irq_info; + sn_msi_info[vector].pci_addr = bus_addr; + + *addr_hi = (u32)(bus_addr >> 32); + *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); + + /* + * In the SN platform, bit 16 is a "send vector" bit which + * must be present in order to move the vector through the system. + */ + *data = 0x100 + (unsigned int)vector; + +#ifdef CONFIG_SMP + set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); +#endif + + return 0; +} + +static void +sn_msi_target(unsigned int vector, unsigned int cpu, + u32 *addr_hi, u32 *addr_lo) +{ + int slice; + nasid_t nasid; + u64 bus_addr; + struct pci_dev *pdev; + struct pcidev_info *sn_pdev; + struct sn_irq_info *sn_irq_info; + struct sn_irq_info *new_irq_info; + struct sn_pcibus_provider *provider; + + sn_irq_info = sn_msi_info[vector].sn_irq_info; + if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) + return; + + /* + * Release XIO resources for the old MSI PCI address + */ + + sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; + pdev = sn_pdev->pdi_linux_pcidev; + provider = SN_PCIDEV_BUSPROVIDER(pdev); + + bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); + (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); + sn_msi_info[vector].pci_addr = 0; + + nasid = cpuid_to_nasid(cpu); + slice = cpuid_to_slice(cpu); + + new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); + sn_msi_info[vector].sn_irq_info = new_irq_info; + if (new_irq_info == NULL) + return; + + /* + * Map the xio address into bus space + */ + + bus_addr = (*provider->dma_map_consistent)(pdev, + new_irq_info->irq_xtalkaddr, + sizeof(new_irq_info->irq_xtalkaddr), + SN_DMA_MSI|SN_DMA_ADDR_XIO); + + sn_msi_info[vector].pci_addr = bus_addr; + *addr_hi = (u32)(bus_addr >> 32); + *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); +} + +struct msi_ops sn_msi_ops = { + .setup = sn_msi_setup, + .teardown = sn_msi_teardown, +#ifdef CONFIG_SMP + .target = sn_msi_target, +#endif +}; + +int +sn_msi_init(void) +{ + sn_msi_info = + kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); + if (! sn_msi_info) + return -ENOMEM; + + msi_register(&sn_msi_ops); + return 0; } -- cgit v1.2.2 From 17d6dc8ff098cc8c57941c82f7702804302b1ea1 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 18 Apr 2006 17:19:52 -0700 Subject: [PATCH] PCI: Ignore pre-set 64-bit BARs on 32-bit platforms [pci] Ignore pre-set 64-bit BARs on 32-bit platforms Currently, Linux always rejects a device which has a pre-set 64-bit address on a 32-bit platform. On systems which do not do PCI initialization in firmware, this causes some devices which don't correctly power up with all BARs zero to fail. This patch makes the kernel automatically zero out such an address (thus treating it as if it had not been set at all, meaning it will assign an address if necessary). I have done this only for devices, not bridges. It seems potentially hazardous to do for bridges. Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..5c4924c27f09 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) res->flags |= pci_calc_resource_flags(l); if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { - pci_read_config_dword(dev, reg+4, &l); + u32 szhi, lhi; + pci_read_config_dword(dev, reg+4, &lhi); + pci_write_config_dword(dev, reg+4, ~0); + pci_read_config_dword(dev, reg+4, &szhi); + pci_write_config_dword(dev, reg+4, lhi); + szhi = pci_size(lhi, szhi, 0xffffffff); next++; #if BITS_PER_LONG == 64 - res->start |= ((unsigned long) l) << 32; + res->start |= ((unsigned long) lhi) << 32; res->end = res->start + sz; - pci_write_config_dword(dev, reg+4, ~0); - pci_read_config_dword(dev, reg+4, &sz); - pci_write_config_dword(dev, reg+4, l); - sz = pci_size(l, sz, 0xffffffff); - if (sz) { + if (szhi) { /* This BAR needs > 4GB? Wow. */ - res->end |= (unsigned long)sz<<32; + res->end |= (unsigned long)szhi<<32; } #else - if (l) { - printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); + if (szhi) { + printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); res->start = 0; res->flags = 0; - continue; + } else if (l) { + /* 64-bit wide address, treat as disabled */ + pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(dev, reg+4, 0); + res->start = 0; + res->end = sz; } #endif } -- cgit v1.2.2 From ea28502d5d0fc624777a8a6b4d6865d282055b05 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 9 Jun 2006 11:28:29 -0700 Subject: [PATCH] PCI: fix to pci ignore pre-set 64-bit bars on 32-bit platforms When we detect a 64-bit pre-set address in a BAR on a 32-bit platform, we disable it and treat it as if it had been unset, thus allowing the general address assignment code to assign a new address to it when the device is enabled. This can happen either if the firmware assigns 64-bit addresses; additionally, some cards have been found "in the wild" which do not come out of reset with all the BAR registers set to zero. Unfortunately, the patch that implemented this tested the low part of the address instead of the high part of the address. This patch fixes that. Signed-off-by: Bjorn Helgaas Signed-off-by: H. Peter Anvin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5c4924c27f09..27148db06ba0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -199,7 +199,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); res->start = 0; res->flags = 0; - } else if (l) { + } else if (lhi) { /* 64-bit wide address, treat as disabled */ pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); pci_write_config_dword(dev, reg+4, 0); -- cgit v1.2.2 From 75acfecaa031c0e1bc412cee4fe58ba49ff3406c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 1 May 2006 10:43:46 -0500 Subject: [PATCH] PCI: Add pci_assign_resource_fixed -- allow fixed address assignments PCI: Add pci_assign_resource_fixed -- allow fixed address assignments On some embedded systems the PCI address for hotplug devices are not only known a priori but are required to be at a given PCI address for other master in the system to be able to access. An example of such a system would be an FPGA which is setup from user space after the system has booted. The FPGA may be access by DSPs in the system and those DSPs expect the FPGA at a fixed PCI address. Added pci_assign_resource_fixed() as a way to allow assignment of the PCI devices's BARs at fixed PCI addresses. Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-res.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return ret; } +#ifdef CONFIG_EMBEDDED +int pci_assign_resource_fixed(struct pci_dev *dev, int resno) +{ + struct pci_bus *bus = dev->bus; + struct resource *res = dev->resource + resno; + unsigned int type_mask; + int i, ret = -EBUSY; + + type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + + /* type_mask must match */ + if ((res->flags ^ r->flags) & type_mask) + continue; + + ret = request_resource(r, res); + + if (ret == 0) + break; + } + + if (ret) { + printk(KERN_ERR "PCI: Failed to allocate %s resource " + "#%d:%llx@%llx for %s\n", + res->flags & IORESOURCE_IO ? "I/O" : "mem", + resno, (unsigned long long)(res->end - res->start + 1), + (unsigned long long)res->start, pci_name(dev)); + } else if (resno < PCI_BRIDGE_RESOURCES) { + pci_update_resource(dev, res, resno); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); +#endif + /* Sort resources by alignment */ void __devinit pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) -- cgit v1.2.2 From 9f125d30487cea72542a84b4835c037163c7f3d5 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 29 Apr 2006 10:59:08 +0200 Subject: [PATCH] PCI: Add a "enable" sysfs attribute to the pci devices to allow userspace (Xorg) to enable devices without doing foul direct access This patch adds an "enable" sysfs attribute to each PCI device. When read it shows the "enabled-ness" of the device, but you can write a "0" into it to disable a device, and a "1" to enable it. This later is needed for X and other cases where userspace wants to enable the BARs on a device (typical example: to run the video bios on a secundary head). Right now X does all this "by hand" via bitbanging, that's just evil. This allows X to no longer do that but to just let the kernel do this. Signed-off-by: Arjan van de Ven CC: Peter Jones Acked-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56ac2bc003c7..37897a8c95e0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -43,6 +43,7 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); pci_config_attr(subsystem_device, "0x%04x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); +pci_config_attr(is_enabled, "%u\n"); static ssize_t local_cpus_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -90,6 +91,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), (u8)(pci_dev->class)); } +static ssize_t +is_enabled_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + /* this can crash the machine when done on the "wrong" device */ + if (!capable(CAP_SYS_ADMIN)) + return count; + + if (*buf == '0') + pci_disable_device(pdev); + + if (*buf == '1') + pci_enable_device(pdev); + + return count; +} + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), @@ -101,6 +121,7 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(irq), __ATTR_RO(local_cpus), __ATTR_RO(modalias), + __ATTR(enable, 0600, is_enabled_show, is_enabled_store), __ATTR_NULL, }; -- cgit v1.2.2 From a1e022b3aeacf633a6c8e8f0eb04d9c9e44b4fcd Mon Sep 17 00:00:00 2001 From: Kristen Accardi Date: Fri, 28 Apr 2006 11:37:38 -0700 Subject: [PATCH] PCI: don't enable device if already enabled If a device is already enabled, don't bother reenabling it. Signed-off-by: Kristen Carlson Accardi Acked-By: Arjan van de Ven Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fde41cc14734..aa480370ef10 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) int pci_enable_device(struct pci_dev *dev) { - int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); + int err; + + if (dev->is_enabled) + return 0; + + err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); if (err) return err; pci_fixup_device(pci_fixup_enable, dev); -- cgit v1.2.2 From 9c273b95808c270149e9be9e172e4ef19f5d5c98 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 28 Apr 2006 00:42:21 -0700 Subject: [PATCH] PCI ACPI: Rename the functions to avoid multiple instances. There were two instances of pci_acpi_init(), one in drivers/pci/pci-acpi.c and another in arch/i386/pci/acpi.c. Rename the one in pci-acpi.c and make it consistent with other names in the same file. Signed-off-by: Muthukumar R Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-acpi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ecae5ff0c1..bb7456c1dbac 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) /* ACPI bus type */ -static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) +static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) { struct pci_dev * pci_dev; acpi_integer addr; @@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) return 0; } -static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) +static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) { int num; unsigned int seg, bus; @@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } -static struct acpi_bus_type pci_acpi_bus = { +static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, - .find_device = pci_acpi_find_device, - .find_bridge = pci_acpi_find_root_bridge, + .find_device = acpi_pci_find_device, + .find_bridge = acpi_pci_find_root_bridge, }; -static int __init pci_acpi_init(void) +static int __init acpi_pci_init(void) { int ret; - ret = register_acpi_bus_type(&pci_acpi_bus); + ret = register_acpi_bus_type(&acpi_pci_bus); if (ret) return 0; platform_pci_choose_state = acpi_pci_choose_state; platform_pci_set_power_state = acpi_pci_set_power_state; return 0; } -arch_initcall(pci_acpi_init); +arch_initcall(acpi_pci_init); -- cgit v1.2.2 From bd8481e1646d7649fa101ee57a5139b9da3c2436 Mon Sep 17 00:00:00 2001 From: Doug Thompson Date: Mon, 8 May 2006 17:06:09 -0700 Subject: [PATCH] PCI Bus Parity Status-broken hardware attribute, EDAC foundation Currently, the EDAC (error detection and correction) modules that are in the kernel contain some features that need to be moved. After some good feedback on the PCI Parity detection code and interface (http://www.ussg.iu.edu/hypermail/linux/kernel/0603.1/0897.html) this patch ADDs an new attribute to the pci_dev structure: Namely the 'broken_parity_status' bit. When set this indicates that the respective hardware generates false positives of Parity errors. The EDAC "blacklist" solution was inferior and will be removed in a future patch. Also in this patch is a PCI quirk.c entry for an Infiniband PCI-X card which generates false positive parity errors. I am requesting comments on this AND on the possibility of a exposing this 'broken_parity_status' bit to userland via the PCI device sysfs directory for devices. This access would allow for enabling of this feature on new devices and for old devices that have their drivers updated. (SLES 9 SP3 did this on an ATI motherboard video device). There is a need to update such a PCI attribute between kernel releases. This patch just adds a storage place for the attribute and a quirk entry for a known bad PCI device. PCI Parity reaper/harvestor operations are in EDAC itself and will be refactored to use this PCI attribute instead of its own mechanisms (which are currently disabled) in the future. Signed-off-by: Doug Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..ea48e969a12e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -24,6 +24,17 @@ #include #include "pci.h" +/* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. + */ +static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) +{ + dev->broken_parity_status = 1; /* This device gives false positives */ +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); + /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ static void __devinit quirk_passive_release(struct pci_dev *dev) -- cgit v1.2.2 From 1edab4a164b229807853682f7ff7858c11dd3481 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 23 May 2006 03:05:27 -0400 Subject: [PATCH] PCI: AMD 8131 MSI quirk called too late, bus_flags not inherited ? The PCI_BUS_FLAGS_NO_MSI bus flags does not appear do be inherited correctly from the amd8131 MSI quirk to its parent busses. It makes devices behind a bridge behind amd8131 try to enable MSI while the amd8131 does not support it. We fix this by looking at flags of all parent busses in pci_enable_msi() and pci_enable_msix(). By the way, also add the missing dev->no_msi check in pci_enable_msix() Signed-off-by: Brice Goglin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f8105783da2f..4aea563bda60 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -916,6 +916,7 @@ static int msix_capability_init(struct pci_dev *dev, **/ int pci_enable_msi(struct pci_dev* dev) { + struct pci_bus *bus; int pos, temp, status = -EINVAL; u16 control; @@ -925,8 +926,9 @@ int pci_enable_msi(struct pci_dev* dev) if (dev->no_msi) return status; - if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) - return -EINVAL; + for (bus = dev->bus; bus; bus = bus->parent) + if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) + return -EINVAL; temp = dev->irq; @@ -1162,6 +1164,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { + struct pci_bus *bus; int status, pos, nr_entries, free_vectors; int i, j, temp; u16 control; @@ -1170,6 +1173,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) if (!pci_msi_enable || !dev || !entries) return -EINVAL; + if (dev->no_msi) + return -EINVAL; + + for (bus = dev->bus; bus; bus = bus->parent) + if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) + return -EINVAL; + status = msi_init(); if (status < 0) return status; -- cgit v1.2.2 From 020d502488bebdbc1b2c2828d996f04e563f082a Mon Sep 17 00:00:00 2001 From: Rajesh Shah Date: Tue, 23 May 2006 10:14:36 -0700 Subject: [PATCH] PCI: Allow MSI to work on kexec kernel We recently ran into a problem where the e1000 device failed to work properly on the kexec kernel. MSI was enabled for the device in the main kernel when it crashed. The e1000 driver tried to enable MSI on the kexec kernel, but the code bailed early when it found that MSI was already enabled in the hardware, even though the software state was not properly set up in the kexec'd kernel. This patch fixes the problem by moving the early return to after making sure that the software state is properly initialized. Signed-off-by: Rajesh Shah Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4aea563bda60..9c69b6966e79 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -940,14 +940,13 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (control & PCI_MSI_FLAGS_ENABLE) - return 0; /* Already in MSI mode */ - if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { /* Lookup Sucess */ unsigned long flags; + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (control & PCI_MSI_FLAGS_ENABLE) + return 0; /* Already in MSI mode */ spin_lock_irqsave(&msi_lock, flags); if (!vector_irq[dev->irq]) { msi_desc[dev->irq]->msi_attrib.state = 0; -- cgit v1.2.2 From 99dc804d9bcc2c53f4c20c291bf4e185312a1a0c Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 26 May 2006 10:58:27 +0800 Subject: [PATCH] PCI: disable msi mode in pci_disable_device Brice said the pci_save_msi_state breaks his driver in his special usage (not in suspend/resume), as pci_save_msi_state will disable msi mode. In his usage, pci_save_state will be called at runtime, and later (after the device operates for some time and has an error) pci_restore_state will be called. In another hand, suspend/resume needs disable msi mode, as device should stop working completely. This patch try to workaround this issue. Drivers are expected call pci_disable_device in suspend time after pci_save_state. Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 6 ++++-- drivers/pci/pci.c | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9c69b6966e79..3ec558dc6523 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -453,9 +453,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) /* Set enabled bits to single MSI & enable MSI_enable bit */ msi_enable(control, 1); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msi_enabled = 1; } else { msix_enable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 1; } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ @@ -472,9 +474,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) /* Set enabled bits to single MSI & enable MSI_enable bit */ msi_disable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msi_enabled = 0; } else { msix_disable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 0; } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ @@ -549,7 +553,6 @@ int pci_save_msi_state(struct pci_dev *dev) pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); if (control & PCI_MSI_FLAGS_MASKBIT) pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); - disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); save_state->cap_nr = PCI_CAP_ID_MSI; pci_add_saved_cap(dev, save_state); return 0; @@ -639,7 +642,6 @@ int pci_save_msix_state(struct pci_dev *dev) } dev->irq = temp; - disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index aa480370ef10..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -551,7 +551,14 @@ void pci_disable_device(struct pci_dev *dev) { u16 pci_command; - + + if (dev->msi_enabled) + disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), + PCI_CAP_ID_MSI); + if (dev->msix_enabled) + disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), + PCI_CAP_ID_MSIX); + pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; -- cgit v1.2.2 From b209a6ee49099b7500abf024f7b6b9648b5a3eac Mon Sep 17 00:00:00 2001 From: "bibo,mao" Date: Wed, 31 May 2006 18:17:33 +0800 Subject: [PATCH] PCI: cleanup unused variable about msi driver In IA64 platform, msi driver does not use irq_vector variable, and in x86 platform LAST_DEVICE_VECTOR should one before FIRST_SYSTEM_VECTOR, this patch modify this. Signed-off-by: bibo, mao Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3ec558dc6523..a81c5b99daf3 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -35,7 +35,6 @@ static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -u8 irq_vector[NR_IRQ_VECTORS]; #endif static struct msi_ops *msi_ops; @@ -383,10 +382,6 @@ static int msi_init(void) return status; } -#ifndef CONFIG_X86_IO_APIC - irq_vector[0] = FIRST_DEVICE_VECTOR; -#endif - if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); -- cgit v1.2.2 From c0da3ba0a29d70c95ed39366a1c9b849f3439fbe Mon Sep 17 00:00:00 2001 From: Kimball Murray Date: Wed, 31 May 2006 14:20:04 -0400 Subject: [PATCH] PCI: don't move ioapics below PCI bridge A recent Stratus x86_64 platform uses a system ioapic that is a PCI device located below a PCI bridge. Other platforms like this may exist. This patch fixes a problem wherein the kernel's PCI setup code moves the ioapic to an address other than that assigned by the BIOS. It simply adds another exclusion (which already includes classless devices and host bridges) to the function pbus_assign_resources_sorted so that it will not move the ioapic. If the ioapic is moved, the fixmap mapping to it is broken, so the OS should leave it alone. From: Kimball Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28ce3a7ee434..35086e80faa9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { u16 class = dev->class >> 8; - /* Don't touch classless devices and host bridges. */ + /* Don't touch classless devices or host bridges or ioapics. */ if (class == PCI_CLASS_NOT_DEFINED || - class == PCI_CLASS_BRIDGE_HOST) + class == PCI_CLASS_BRIDGE_HOST || + class == PCI_CLASS_SYSTEM_PIC) continue; pdev_sort_resources(dev, &head); -- cgit v1.2.2 From f7e6600d762bf7c04b48c8d9bd0ab26d04a8d11f Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Wed, 31 May 2006 23:35:47 -0700 Subject: [PATCH] PCI: remove unneeded msi code The code is really not needed. Roland Dreier/Greg KH removed the release_mem_region() calls that were the only consumers of phys_addr: http://www.ussg.iu.edu/hypermail/linux/kernel/0503.0/1540.html patch below deletes the "dead" code. Signed-off-by: Grant Grundler Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 45 +-------------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a81c5b99daf3..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1060,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - if (head == vector) { - /* - * Detect last MSI-X vector to be released. - * Release the MSI-X memory-mapped table. - */ -#if 0 - int pos, nr_entries; - unsigned long phys_addr; - u32 table_offset; - u16 control; - u8 bir; - - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - 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); - bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); - table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; - phys_addr = pci_resource_start(dev, bir) + table_offset; -/* - * FIXME! and what did you want to do with phys_addr? - */ -#endif + if (head == vector) iounmap(base); - } } return 0; @@ -1360,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) } msi_free_vector(dev, vector, 0); if (warning) { - /* Force to release the MSI-X memory-mapped table */ -#if 0 - unsigned long phys_addr; - u32 table_offset; - u16 control; - u8 bir; - - pci_read_config_word(dev, msi_control_reg(pos), - &control); - pci_read_config_dword(dev, msix_table_offset_reg(pos), - &table_offset); - bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); - table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; - phys_addr = pci_resource_start(dev, bir) + table_offset; -/* - * FIXME! and what did you want to do with phys_addr? - */ -#endif iounmap(base); printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " "called without free_irq() on all MSI-X vectors\n", -- cgit v1.2.2 From d71374dafbba7ec3f67371d3b7e9f6310a588808 Mon Sep 17 00:00:00 2001 From: Zhang Yanmin Date: Fri, 2 Jun 2006 12:35:43 +0800 Subject: [PATCH] PCI: fix race with pci_walk_bus and pci_destroy_dev pci_walk_bus has a race with pci_destroy_dev. When cb is called in pci_walk_bus, pci_destroy_dev might unlink the dev pointed by next. Later on in the next loop, pointer next becomes NULL and cause kernel panic. Below patch against 2.6.17-rc4 fixes it by changing pci_bus_lock (spin_lock) to pci_bus_sem (rw_semaphore). Signed-off-by: Zhang Yanmin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/bus.c | 21 +++++++++------------ drivers/pci/pci.h | 2 +- drivers/pci/probe.c | 17 +++++++++-------- drivers/pci/remove.c | 12 ++++++------ drivers/pci/search.c | 32 ++++++++++++++++---------------- 5 files changed, 41 insertions(+), 43 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index eed67d9e73bc..723092682023 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) { device_add(&dev->dev); - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_add_tail(&dev->global_list, &pci_devices); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); pci_proc_attach_device(dev); pci_create_sysfs_dev_files(dev); @@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) */ if (dev->subordinate) { if (list_empty(&dev->subordinate->node)) { - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_add_tail(&dev->subordinate->node, &dev->bus->children); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); } pci_bus_add_devices(dev->subordinate); @@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), struct list_head *next; bus = top; - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); next = top->devices.next; for (;;) { if (next == &bus->devices) { @@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), continue; } dev = list_entry(next, struct pci_dev, bus_list); - pci_dev_get(dev); if (dev->subordinate) { /* this is a pci-pci bridge, do its devices next */ next = dev->subordinate->devices.next; bus = dev->subordinate; } else next = dev->bus_list.next; - spin_unlock(&pci_bus_lock); - /* Run device routines with the bus unlocked */ + /* Run device routines with the device locked */ + down(&dev->dev.sem); cb(dev, userdata); - - spin_lock(&pci_bus_lock); - pci_dev_put(dev); + up(&dev->dev.sem); } - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); } EXPORT_SYMBOL_GPL(pci_walk_bus); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 30630cbe2fe3..29bdeca031a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int extern void pci_remove_legacy_files(struct pci_bus *bus); /* Lock for read/write access to pci device and bus lists */ -extern spinlock_t pci_bus_lock; +extern struct rw_semaphore pci_bus_sem; #ifdef CONFIG_X86_IO_APIC extern int pci_msi_quirk; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 27148db06ba0..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -383,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de child = pci_alloc_child_bus(parent, dev, busnr); if (child) { - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_add_tail(&child->node, &parent->children); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); } return child; } @@ -844,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) * and the bus list for fixup functions, etc. */ INIT_LIST_HEAD(&dev->global_list); - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_add_tail(&dev->bus_list, &bus->devices); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); } struct pci_dev * __devinit @@ -981,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } - spin_lock(&pci_bus_lock); + + down_write(&pci_bus_sem); list_add_tail(&b->node, &pci_root_buses); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); memset(dev, 0, sizeof(*dev)); dev->parent = parent; @@ -1023,9 +1024,9 @@ class_dev_create_file_err: class_dev_reg_err: device_unregister(dev); dev_reg_err: - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_del(&b->node); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); err_out: kfree(dev); kfree(b); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1a6bf9de166f..99ffbd478b29 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev) pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); device_unregister(&dev->dev); - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_del(&dev->global_list); dev->global_list.next = dev->global_list.prev = NULL; - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); } /* Remove the device from the device lists, and prevent any further * list accesses from this device */ - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_del(&dev->bus_list); dev->bus_list.next = dev->bus_list.prev = NULL; - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); pci_free_resources(dev); pci_dev_put(dev); @@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) { pci_proc_detach_bus(pci_bus); - spin_lock(&pci_bus_lock); + down_write(&pci_bus_sem); list_del(&pci_bus->node); - spin_unlock(&pci_bus_lock); + up_write(&pci_bus_sem); pci_remove_legacy_files(pci_bus); class_device_remove_file(&pci_bus->class_dev, &class_device_attr_cpuaffinity); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ce7dd6e7be60..622b3f8ba820 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -13,7 +13,7 @@ #include #include "pci.h" -DEFINE_SPINLOCK(pci_bus_lock); +DECLARE_RWSEM(pci_bus_sem); static struct pci_bus * __devinit pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) @@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from) struct pci_bus *b = NULL; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) b = pci_bus_b(n); - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); return b; } @@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) struct pci_dev *dev; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); list_for_each(tmp, &bus->devices) { dev = pci_dev_b(tmp); @@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) dev = NULL; out: pci_dev_get(dev); - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); return dev; } @@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, struct pci_dev *dev; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; while (n && (n != &pci_devices)) { @@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, } dev = NULL; exit: - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); return dev; } @@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, struct pci_dev *dev; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; while (n && (n != &pci_devices)) { @@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, dev = NULL; exit: dev = pci_dev_get(dev); - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); pci_dev_put(from); return dev; } @@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p struct pci_dev *dev; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); n = from ? from->global_list.prev : pci_devices.prev; while (n && (n != &pci_devices)) { @@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p } dev = NULL; exit: - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); return dev; } @@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) struct pci_dev *dev; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; while (n && (n != &pci_devices)) { @@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) dev = NULL; exit: dev = pci_dev_get(dev); - spin_unlock(&pci_bus_lock); + up_read(&pci_bus_sem); pci_dev_put(from); return dev; } @@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids) int found = 0; WARN_ON(in_interrupt()); - spin_lock(&pci_bus_lock); + down_read(&pci_bus_sem); while (ids->vendor || ids->subvendor || ids->class_mask) { list_for_each_entry(dev, &pci_devices, global_list) { if (pci_match_one_device(ids, dev)) { @@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids) } ids++; } -exit: - spin_unlock(&pci_bus_lock); +exit: + up_read(&pci_bus_sem); return found; } EXPORT_SYMBOL(pci_dev_present); -- cgit v1.2.2 From bd91fde952b0aa80c820857241ff1923537d2bde Mon Sep 17 00:00:00 2001 From: Chris Wedgwood Date: Mon, 5 Jun 2006 00:13:21 -0700 Subject: [PATCH] PCI: MSI-K8T-Neo2-Fir: run only where needed Be more selective when running the MSI-K8T-Neo2Fir soundcard PCI quirk so as not to run this on hardware where it's probably not needed. Signed-off-by: Chris Wedgwood Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ea48e969a12e..aea4d49bcce3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -889,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e * when a PCI-Soundcard is added. The BIOS only gives Options * "Disabled" and "AUTO". This Quirk Sets the corresponding * Register-Value to enable the Soundcard. + * + * FIXME: Presently this quirk will run on anything that has an 8237 + * which isn't correct, we need to check DMI tables or something in + * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it + * runs everywhere at present we suppress the printk output in most + * irrelevant cases. */ static void __init k8t_sound_hostbridge(struct pci_dev *dev) { unsigned char val; - printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n"); pci_read_config_byte(dev, 0x50, &val); if (val == 0x88 || val == 0xc8) { + /* Assume it's probably a MSI-K8T-Neo2Fir */ + printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); pci_write_config_byte(dev, 0x50, val & (~0x40)); /* Verify the Change for Status output */ pci_read_config_byte(dev, 0x50, &val); if (val & 0x40) - printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n"); + printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); else - printk(KERN_INFO "PCI: MSI-K8T soundcard on\n"); - } else { - printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: " - "no Change!\n"); + printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); } - } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); -- cgit v1.2.2 From bdee9d98d281d84718eaff6bf0dd2b6ad418b36f Mon Sep 17 00:00:00 2001 From: Doug Thompson Date: Wed, 14 Jun 2006 16:59:48 -0700 Subject: [PATCH] PCI: Bus Parity Status sysfs interface From: Doug Thompson This patch adds the 'broken_parity_status' sysfs attribute file to a PCI device. Reading this attribute a userland program can determine if PCI device provides false positives (value of 1) in its generation of PCI Parity status, or not (value of 0). As PCI devices are found to be 'bad' in this regard, userland programs can also set the appropriate value (root access only) of a faulty device. This per device information will be used in the EDAC PCI Parity scanner code in a future patch once this interface becomes available. Signed-off-by: Doug Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 37897a8c95e0..bc405c035ce3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -45,6 +45,28 @@ pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); pci_config_attr(is_enabled, "%u\n"); +static ssize_t broken_parity_status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + return sprintf (buf, "%u\n", pdev->broken_parity_status); +} + +static ssize_t broken_parity_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + ssize_t consumed = -EINVAL; + + if ((count > 0) && (*buf == '0' || *buf == '1')) { + pdev->broken_parity_status = *buf == '1' ? 1 : 0; + consumed = count; + } + return consumed; +} + static ssize_t local_cpus_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -122,6 +144,8 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(local_cpus), __ATTR_RO(modalias), __ATTR(enable, 0600, is_enabled_show, is_enabled_store), + __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), + broken_parity_status_show,broken_parity_status_store), __ATTR_NULL, }; -- cgit v1.2.2 From cf34a8e07f02c76f3f1232eecb681301a3d7b10b Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 13 Jun 2006 14:35:42 -0400 Subject: [PATCH] PCI: nVidia quirk to make AER PCI-E extended capability visible The nVidia CK804 PCI-E chipset supports the AER extended capability but sometimes fails to link it (with some BIOS or after a warm reboot). It makes the AER cap invisible to pci_find_ext_capability(). The patch adds a quirk to set the missing bit that controls the linking of the capability. By the way, it removes the corresponding code in the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: Loic Prylli Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index aea4d49bcce3..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1499,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); +/* Under some circumstances, AER is not linked with extended capabilities. + * Force it to be linked by setting the corresponding control bit in the + * config space. + */ +static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) +{ + uint8_t b; + if (pci_read_config_byte(dev, 0xf41, &b) == 0) { + if (!(b & 0x20)) { + pci_write_config_byte(dev, 0xf41, b | 0x20); + printk(KERN_INFO + "PCI: Linking AER extended capability on %s\n", + pci_name(dev)); + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, + quirk_nvidia_ck804_pcie_aer_ext_cap); + EXPORT_SYMBOL(pcie_mch_quirk); #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_fixup_device); -- cgit v1.2.2