diff options
Diffstat (limited to 'drivers/pci/hotplug')
59 files changed, 8426 insertions, 16787 deletions
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 2f1289eebb3..df8caec5978 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -2,49 +2,21 @@ # PCI Hotplug support # -menu "PCI Hotplug Support" - -config HOTPLUG_PCI - tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - select HOTPLUG +menuconfig HOTPLUG_PCI + bool "Support for PCI Hotplug" + depends on PCI && SYSFS ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is - powered up and running. The file system pcihpfs must be mounted - in order to interact with any PCI Hotplug controllers. - - To compile this driver as a module, choose M here: the - module will be called pci_hotplug. + powered up and running. When in doubt, say N. -config HOTPLUG_PCI_FAKE - tristate "Fake PCI Hotplug driver" - depends on HOTPLUG_PCI - help - Say Y here if you want to use the fake PCI hotplug driver. It can - be used to simulate PCI hotplug events if even if your system is - not PCI hotplug capable. - - This driver will "emulate" removing PCI devices from the system. - If the "power" file is written to with "0" then the specified PCI - device will be completely removed from the kernel. - - WARNING, this does NOT turn off the power to the PCI device. - This is a "logical" removal, not a physical or electrical - removal. - - Use this module at your own risk. You have been warned! - - To compile this driver as a module, choose M here: the - module will be called fakephp. - - When in doubt, say N. +if HOTPLUG_PCI config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" - depends on HOTPLUG_PCI && X86 && PCI_BIOS + depends on X86 && PCI_BIOS help Say Y here if you have a motherboard with a Compaq PCI Hotplug controller. @@ -66,7 +38,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM config HOTPLUG_PCI_IBM tristate "IBM PCI Hotplug driver" - depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS + depends on X86_IO_APIC && X86 && PCI_BIOS help Say Y here if you have a motherboard with a IBM PCI Hotplug controller. @@ -77,15 +49,12 @@ config HOTPLUG_PCI_IBM When in doubt, say N. config HOTPLUG_PCI_ACPI - tristate "ACPI PCI Hotplug driver" - depends on ACPI && HOTPLUG_PCI + bool "ACPI PCI Hotplug driver" + depends on HOTPLUG_PCI=y && ((!ACPI_DOCK && ACPI) || (ACPI_DOCK)) help Say Y here if you have a system that supports PCI Hotplug using ACPI. - To compile this driver as a module, choose M here: the - module will be called acpiphp. - When in doubt, say N. config HOTPLUG_PCI_ACPI_IBM @@ -102,7 +71,6 @@ config HOTPLUG_PCI_ACPI_IBM config HOTPLUG_PCI_CPCI bool "CompactPCI Hotplug driver" - depends on HOTPLUG_PCI help Say Y here if you have a CompactPCI system card with CompactPCI hotswap support per the PICMG 2.1 specification. @@ -111,7 +79,7 @@ config HOTPLUG_PCI_CPCI config HOTPLUG_PCI_CPCI_ZT5550 tristate "Ziatech ZT5550 CompactPCI Hotplug driver" - depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI_CPCI && X86 help Say Y here if you have an Performance Technologies (formerly Intel, formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. @@ -123,7 +91,7 @@ config HOTPLUG_PCI_CPCI_ZT5550 config HOTPLUG_PCI_CPCI_GENERIC tristate "Generic port I/O CompactPCI Hotplug driver" - depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI_CPCI && X86 help Say Y here if you have a CompactPCI system card that exposes the #ENUM hotswap signal as a bit in a system register that can be read through @@ -136,7 +104,6 @@ config HOTPLUG_PCI_CPCI_GENERIC config HOTPLUG_PCI_SHPC tristate "SHPC PCI Hotplug driver" - depends on HOTPLUG_PCI help Say Y here if you have a motherboard with a SHPC PCI Hotplug controller. @@ -146,27 +113,11 @@ config HOTPLUG_PCI_SHPC When in doubt, say N. -config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_SHPC - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - -config HOTPLUG_PCI_SHPC_PHPRM_LEGACY - bool "For AMD SHPC only: Use $HRT for resource/configuration" - depends on HOTPLUG_PCI_SHPC && !ACPI - help - Say Y here for AMD SHPC. You have to select this option if you are - using this driver on platform with AMD SHPC. - config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" - depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE + depends on PPC_PSERIES && EEH help - Say Y here if you have a a RPA system that supports PCI Hotplug. + Say Y here if you have a RPA system that supports PCI Hotplug. To compile this driver as a module, choose M here: the module will be called rpaphp. @@ -182,17 +133,27 @@ config HOTPLUG_PCI_RPA_DLPAR To compile this driver as a module, choose M here: the module will be called rpadlpar_io. - - When in doubt, say N. + + When in doubt, say N. config HOTPLUG_PCI_SGI tristate "SGI PCI Hotplug Support" - depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) + depends on IA64_SGI_SN2 || IA64_GENERIC help Say Y here if you want to use the SGI Altix Hotplug Driver for PCI devices. When in doubt, say N. -endmenu +config HOTPLUG_PCI_S390 + bool "System z PCI Hotplug Support" + depends on S390 && 64BIT + help + Say Y here if you want to use the System z PCI Hotplug + driver for PCI devices. Without this driver it is not + possible to access stand-by PCI functions nor to deconfigure + PCI functions. + + When in doubt, say Y. +endif # HOTPLUG_PCI diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 3c71e3077ff..3e6532b945c 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -3,25 +3,36 @@ # obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o + +# native drivers should be linked before acpiphp in order to allow the +# native driver to attempt to bind first. We can then fall back to +# generic support. + +obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o -obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o -pci_hotplug-objs := pci_hotplug_core.o +# acpiphp_ibm extends acpiphp, so should be linked afterwards. + +obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o + +pci_hotplug-objs := pci_hotplug_core.o pcihp_slot.o ifdef CONFIG_HOTPLUG_PCI_CPCI pci_hotplug-objs += cpci_hotplug_core.o \ cpci_hotplug_pci.o endif +ifdef CONFIG_ACPI +pci_hotplug-objs += acpi_pcihp.o +endif cpqphp-objs := cpqphp_core.o \ cpqphp_ctrl.o \ @@ -51,9 +62,7 @@ pciehp-objs := pciehp_core.o \ pciehp_pci.o \ pciehp_hpc.o ifdef CONFIG_ACPI - pciehp-objs += pciehprm_acpi.o -else - pciehp-objs += pciehprm_nonacpi.o +pciehp-objs += pciehp_acpi.o endif shpchp-objs := shpchp_core.o \ @@ -61,12 +70,3 @@ shpchp-objs := shpchp_core.o \ shpchp_pci.o \ shpchp_sysfs.o \ shpchp_hpc.o -ifdef CONFIG_ACPI - shpchp-objs += shpchprm_acpi.o -else - ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY - shpchp-objs += shpchprm_legacy.o - else - shpchp-objs += shpchprm_nonacpi.o - endif -endif diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c new file mode 100644 index 00000000000..a94d850ae22 --- /dev/null +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -0,0 +1,477 @@ +/* + * Common ACPI functions for hot plug platforms + * + * Copyright (C) 2006 Intel Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <kristen.c.accardi@intel.com> + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/pci_hotplug.h> +#include <linux/acpi.h> +#include <linux/pci-acpi.h> +#include <linux/slab.h> + +#define MY_NAME "acpi_pcihp" + +#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## 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_OSHP "OSHP" + +static bool 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", + __func__, 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", + __func__, 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", + __func__, 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", + __func__, 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) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package, *fields; + int i; + + memset(hpp, 0, sizeof(struct hotplug_params)); + + status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); + if (ACPI_FAILURE(status)) + return status; + + package = (union acpi_object *) buffer.pointer; + if (package->type != ACPI_TYPE_PACKAGE || + package->package.count != 4) { + status = AE_ERROR; + goto exit; + } + + fields = package->package.elements; + for (i = 0; i < 4; i++) { + if (fields[i].type != ACPI_TYPE_INTEGER) { + status = AE_ERROR; + goto exit; + } + } + + hpp->t0 = &hpp->type0_data; + hpp->t0->revision = 1; + hpp->t0->cache_line_size = fields[0].integer.value; + hpp->t0->latency_timer = fields[1].integer.value; + hpp->t0->enable_serr = fields[2].integer.value; + hpp->t0->enable_perr = fields[3].integer.value; + +exit: + kfree(buffer.pointer); + return status; +} + + + +/* acpi_run_oshp - get control of hotplug from the firmware + * + * @handle - the handle of the hotplug controller. + */ +static acpi_status acpi_run_oshp(acpi_handle handle) +{ + acpi_status status; + struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); + + /* run OSHP */ + status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); + if (ACPI_FAILURE(status)) + if (status != AE_NOT_FOUND) + printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", + __func__, (char *)string.pointer, status); + else + dbg("%s:%s OSHP not found\n", + __func__, (char *)string.pointer); + else + pr_debug("%s:%s OSHP passes\n", __func__, + (char *)string.pointer); + + kfree(string.pointer); + return status; +} + +/* pci_get_hp_params + * + * @dev - the pci_dev for which we want parameters + * @hpp - allocated by the caller + */ +int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) +{ + acpi_status status; + acpi_handle handle, phandle; + struct pci_bus *pbus; + + handle = NULL; + for (pbus = dev->bus; pbus; pbus = pbus->parent) { + handle = acpi_pci_get_bridge_handle(pbus); + if (handle) + break; + } + + /* + * _HPP settings apply to all child buses, until another _HPP is + * encountered. If we don't find an _HPP for the input pci dev, + * look for it in the parent device scope since that would apply to + * this pci dev. + */ + while (handle) { + status = acpi_run_hpx(handle, hpp); + if (ACPI_SUCCESS(status)) + return 0; + status = acpi_run_hpp(handle, hpp); + if (ACPI_SUCCESS(status)) + return 0; + if (acpi_is_root_bridge(handle)) + break; + status = acpi_get_parent(handle, &phandle); + if (ACPI_FAILURE(status)) + break; + handle = phandle; + } + return -ENODEV; +} +EXPORT_SYMBOL_GPL(pci_get_hp_params); + +/** + * acpi_get_hp_hw_control_from_firmware + * @dev: the pci_dev of the bridge that has a hotplug controller + * @flags: requested control bits for _OSC + * + * Attempt to take hotplug control from firmware. + */ +int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) +{ + acpi_status status; + acpi_handle chandle, handle; + struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; + + flags &= OSC_PCI_SHPC_NATIVE_HP_CONTROL; + if (!flags) { + err("Invalid flags %u specified!\n", flags); + return -EINVAL; + } + + /* + * Per PCI firmware specification, we should run the ACPI _OSC + * method to get control of hotplug hardware before using it. If + * an _OSC is missing, we look for an OSHP to do the same thing. + * To handle different BIOS behavior, we look for _OSC on a root + * bridge preferentially (according to PCI fw spec). Later for + * OSHP within the scope of the hotplug controller and its parents, + * up to the host bridge under which this controller exists. + */ + handle = acpi_find_root_bridge_handle(pdev); + if (handle) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); + dbg("Trying to get hotplug control for %s\n", + (char *)string.pointer); + status = acpi_pci_osc_control_set(handle, &flags, flags); + if (ACPI_SUCCESS(status)) + goto got_one; + if (status == AE_SUPPORT) + goto no_control; + kfree(string.pointer); + string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; + } + + handle = ACPI_HANDLE(&pdev->dev); + if (!handle) { + /* + * This hotplug controller was not listed in the ACPI name + * space at all. Try to get acpi handle of parent pci bus. + */ + struct pci_bus *pbus; + for (pbus = pdev->bus; pbus; pbus = pbus->parent) { + handle = acpi_pci_get_bridge_handle(pbus); + if (handle) + break; + } + } + + while (handle) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); + dbg("Trying to get hotplug control for %s \n", + (char *)string.pointer); + status = acpi_run_oshp(handle); + if (ACPI_SUCCESS(status)) + goto got_one; + if (acpi_is_root_bridge(handle)) + break; + chandle = handle; + status = acpi_get_parent(chandle, &handle); + if (ACPI_FAILURE(status)) + break; + } +no_control: + dbg("Cannot get control of hotplug hardware for pci %s\n", + pci_name(pdev)); + kfree(string.pointer); + return -ENODEV; +got_one: + dbg("Gained control for hotplug HW for pci %s (%s)\n", + pci_name(pdev), (char *)string.pointer); + kfree(string.pointer); + return 0; +} +EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); + +static int pcihp_is_ejectable(acpi_handle handle) +{ + acpi_status status; + unsigned long long removable; + if (!acpi_has_method(handle, "_ADR")) + return 0; + if (acpi_has_method(handle, "_EJ0")) + return 1; + status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); + if (ACPI_SUCCESS(status) && removable) + return 1; + return 0; +} + +/** + * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot + * @pbus: the PCI bus of the PCI slot corresponding to 'handle' + * @handle: ACPI handle to check + * + * Return 1 if handle is ejectable PCI slot, 0 otherwise. + */ +int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle) +{ + acpi_handle bridge_handle, parent_handle; + + if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus))) + return 0; + if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle)))) + return 0; + if (bridge_handle != parent_handle) + return 0; + return pcihp_is_ejectable(handle); +} +EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); + +static acpi_status +check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *found = (int *)context; + if (pcihp_is_ejectable(handle)) { + *found = 1; + return AE_CTRL_TERMINATE; + } + return AE_OK; +} + +/** + * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots + * @handle - handle of the PCI bus to scan + * + * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise. + */ +int acpi_pci_detect_ejectable(acpi_handle handle) +{ + int found = 0; + + if (!handle) + return found; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + check_hotplug, NULL, (void *)&found, NULL); + return found; +} +EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); + +module_param(debug_acpi, bool, 0644); +MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 293603e1b7c..b0e61bf261a 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -36,22 +36,10 @@ #define _ACPIPHP_H #include <linux/acpi.h> -#include <linux/kobject.h> /* for KOBJ_NAME_LEN */ -#include "pci_hotplug.h" - -#define dbg(format, arg...) \ - do { \ - if (acpiphp_debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## 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) - -/* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE KOBJ_NAME_LEN /* {_SUN} */ +#include <linux/mutex.h> +#include <linux/pci_hotplug.h> +struct acpiphp_context; struct acpiphp_bridge; struct acpiphp_slot; @@ -59,41 +47,30 @@ struct acpiphp_slot; * struct slot - slot information for each *physical* slot */ struct slot { - u8 number; struct hotplug_slot *hotplug_slot; - struct list_head slot_list; - struct acpiphp_slot *acpi_slot; + struct hotplug_slot_info info; + unsigned int sun; /* ACPI _SUN (Slot User Number) value */ }; -/** - * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters - * @cache_line_size in DWORD - * @latency_timer in PCI clock - * @enable_SERR 0 or 1 - * @enable_PERR 0 or 1 - */ -struct hpp_param { - u8 cache_line_size; - u8 latency_timer; - u8 enable_SERR; - u8 enable_PERR; -}; - +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} -/** +/* * struct acpiphp_bridge - PCI bridge information * * for each bridge device in ACPI namespace */ struct acpiphp_bridge { struct list_head list; - acpi_handle handle; - struct acpiphp_slot *slots; - int type; - int nr_slots; + struct list_head slots; + struct kref ref; - u32 flags; + struct acpiphp_context *context; + + int nr_slots; /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ struct pci_bus *pci_bus; @@ -101,53 +78,81 @@ struct acpiphp_bridge { /* PCI-to-PCI bridge device */ struct pci_dev *pci_dev; - /* ACPI 2.0 _HPP parameters */ - struct hpp_param hpp; - - spinlock_t res_lock; + bool is_going_away; }; -/** +/* * struct acpiphp_slot - PCI slot information * * PCI slot information for each *physical* PCI slot */ struct acpiphp_slot { - struct acpiphp_slot *next; - struct acpiphp_bridge *bridge; /* parent */ + struct list_head node; + struct pci_bus *bus; struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ - struct semaphore crit_sect; + struct slot *slot; - u32 id; /* slot id (serial #) for hotplug core */ u8 device; /* pci device# */ - - u32 sun; /* ACPI _SUN (slot unique number) */ - u32 slotno; /* slot number relative to bridge */ u32 flags; /* see below */ }; -/** +/* * struct acpiphp_func - PCI function information * * PCI function information for each object in ACPI namespace * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { - struct acpiphp_slot *slot; /* parent */ + struct acpiphp_bridge *parent; + struct acpiphp_slot *slot; struct list_head sibling; - struct pci_dev *pci_dev; - - acpi_handle handle; u8 function; /* pci function# */ u32 flags; /* see below */ }; -/** +struct acpiphp_context { + struct acpi_hotplug_context hp; + struct acpiphp_func func; + struct acpiphp_bridge *bridge; + unsigned int refcount; +}; + +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + +static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) +{ + return container_of(func, struct acpiphp_context, func); +} + +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->hp.self; +} + +static inline acpi_handle func_to_handle(struct acpiphp_func *func) +{ + return func_to_acpi_device(func)->handle; +} + +struct acpiphp_root_context { + struct acpi_hotplug_context hp; + struct acpiphp_bridge *root_bridge; +}; + +static inline struct acpiphp_root_context *to_acpiphp_root_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_root_context, hp); +} + +/* * struct acpiphp_attention_info - device specific attention registration * * ACPI has no generic method of setting/getting attention status @@ -160,66 +165,38 @@ struct acpiphp_attention_info struct module *owner; }; -/* PCI bus bridge HID */ -#define ACPI_PCI_HOST_HID "PNP0A03" - -/* PCI BRIDGE type */ -#define BRIDGE_TYPE_HOST 0 -#define BRIDGE_TYPE_P2P 1 - /* ACPI _STA method value (ignore bit 4; battery present) */ -#define ACPI_STA_PRESENT (0x00000001) -#define ACPI_STA_ENABLED (0x00000002) -#define ACPI_STA_SHOW_IN_UI (0x00000004) -#define ACPI_STA_FUNCTIONING (0x00000008) #define ACPI_STA_ALL (0x0000000f) -/* bridge flags */ -#define BRIDGE_HAS_STA (0x00000001) -#define BRIDGE_HAS_EJ0 (0x00000002) -#define BRIDGE_HAS_HPP (0x00000004) -#define BRIDGE_HAS_PS0 (0x00000010) -#define BRIDGE_HAS_PS1 (0x00000020) -#define BRIDGE_HAS_PS2 (0x00000040) -#define BRIDGE_HAS_PS3 (0x00000080) - /* slot flags */ -#define SLOT_POWEREDON (0x00000001) -#define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (0x00000004) +#define SLOT_ENABLED (0x00000001) +#define SLOT_IS_GOING_AWAY (0x00000002) /* function flags */ #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_PS0 (0x00000010) -#define FUNC_HAS_PS1 (0x00000020) -#define FUNC_HAS_PS2 (0x00000040) -#define FUNC_HAS_PS3 (0x00000080) /* function prototypes */ /* acpiphp_core.c */ -extern int acpiphp_register_attention(struct acpiphp_attention_info*info); -extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); +int acpiphp_register_attention(struct acpiphp_attention_info*info); +int acpiphp_unregister_attention(struct acpiphp_attention_info *info); +int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun); +void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); /* acpiphp_glue.c */ -extern int acpiphp_glue_init (void); -extern void acpiphp_glue_exit (void); -extern int acpiphp_get_num_slots (void); -extern struct acpiphp_slot *get_slot_from_id (int id); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); -extern int acpiphp_enable_slot (struct acpiphp_slot *slot); -extern int acpiphp_disable_slot (struct acpiphp_slot *slot); -extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); -extern u32 acpiphp_get_address (struct acpiphp_slot *slot); +int acpiphp_enable_slot(struct acpiphp_slot *slot); +int acpiphp_disable_slot(struct acpiphp_slot *slot); +u8 acpiphp_get_power_status(struct acpiphp_slot *slot); +u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); +u8 acpiphp_get_latch_status(struct acpiphp_slot *slot); +u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot); /* variables */ -extern int acpiphp_debug; +extern bool acpiphp_disabled; #endif /* _ACPIPHP_H */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 60c4c38047a..e291efcd02a 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -27,32 +27,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to <gregkh@us.ibm.com>, - * <t-kochi@bq.jp.nec.com> + * Send feedback to <kristen.c.accardi@intel.com> * */ +#define pr_fmt(fmt) "acpiphp: " fmt + #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci-acpi.h> +#include <linux/pci_hotplug.h> #include <linux/slab.h> #include <linux/smp.h> -#include <linux/smp_lock.h> -#include "pci_hotplug.h" #include "acpiphp.h" -static LIST_HEAD(slot_list); - -#define MY_NAME "acpiphp" +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 21 /* {_SUN} */ -static int debug; -int acpiphp_debug; +bool acpiphp_disabled; /* local variables */ -static int num_slots; static struct acpiphp_attention_info *attention_info; #define DRIVER_VERSION "0.5" @@ -62,24 +60,18 @@ static struct acpiphp_attention_info *attention_info; MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -module_param(debug, bool, 0644); - -/* export the attention callback registration methods */ -EXPORT_SYMBOL_GPL(acpiphp_register_attention); -EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); +MODULE_PARM_DESC(disable, "disable acpiphp driver"); +module_param_named(disable, acpiphp_disabled, bool, 0444); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); static int set_attention_status (struct hotplug_slot *slot, u8 value); 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_address (struct hotplug_slot *slot, u32 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops acpi_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, @@ -87,18 +79,16 @@ static struct hotplug_slot_ops acpi_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, }; - /** * acpiphp_register_attention - set attention LED callback * @info: must be completely filled with LED callbacks * - * Description: this is used to register a hardware specific ACPI + * Description: This is used to register a hardware specific ACPI * driver that manipulates the attention LED. All the fields in * info must be set. - **/ + */ int acpiphp_register_attention(struct acpiphp_attention_info *info) { int retval = -EINVAL; @@ -110,16 +100,17 @@ int acpiphp_register_attention(struct acpiphp_attention_info *info) } return retval; } +EXPORT_SYMBOL_GPL(acpiphp_register_attention); /** * acpiphp_unregister_attention - unset attention LED callback * @info: must match the pointer used to register * - * Description: this is used to un-register a hardware specific acpi - * driver that manipulates the attention LED. The pointer to the + * Description: This is used to un-register a hardware specific acpi + * driver that manipulates the attention LED. The pointer to the * info struct must be the same as the one used to set it. - **/ + */ int acpiphp_unregister_attention(struct acpiphp_attention_info *info) { int retval = -EINVAL; @@ -130,6 +121,7 @@ int acpiphp_unregister_attention(struct acpiphp_attention_info *info) } return retval; } +EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); /** @@ -137,13 +129,12 @@ int acpiphp_unregister_attention(struct acpiphp_attention_info *info) * @hotplug_slot: slot to enable * * Actual tasks are done in acpiphp_enable_slot() - * */ static int enable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* enable the specified slot */ return acpiphp_enable_slot(slot->acpi_slot); @@ -155,42 +146,42 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) * @hotplug_slot: slot to disable * * Actual tasks are done in acpiphp_disable_slot() - * */ static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* disable the specified slot */ return acpiphp_disable_slot(slot->acpi_slot); } - /** - * set_attention_status - set attention LED +/** + * set_attention_status - set attention LED * @hotplug_slot: slot to set attention LED on * @status: value to set attention LED to (0 or 1) * * attention status LED, so we use a callback that * was registered with us. This allows hardware specific * ACPI implementations to blink the light for us. - **/ - static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) - { + */ +static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) +{ int retval = -ENODEV; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + pr_debug("%s - physical_slot = %s\n", __func__, + hotplug_slot_name(hotplug_slot)); + if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->set_attn(hotplug_slot, status); module_put(attention_info->owner); } else attention_info = NULL; return retval; - } - +} + /** * get_power_status - get power status of a slot @@ -199,13 +190,12 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) * * Some platforms may not implement _STA method properly. * In that case, the value returned may not be reliable. - * */ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_power_status(slot->acpi_slot); @@ -213,7 +203,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) } - /** +/** * get_attention_status - get attention LED status * @hotplug_slot: slot to get status from * @value: returns with value of attention LED @@ -221,13 +211,14 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) * ACPI doesn't have known method to determine the state * of the attention status LED, so we use a callback that * was registered with us. This allows hardware specific - * ACPI implementations to determine its state - **/ + * ACPI implementations to determine its state. + */ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { int retval = -EINVAL; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, + hotplug_slot_name(hotplug_slot)); if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->get_attn(hotplug_slot, value); @@ -244,14 +235,13 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) * @value: pointer to store status * * ACPI doesn't provide any formal means to access latch status. - * Instead, we fake latch status from _STA - * + * Instead, we fake latch status from _STA. */ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_latch_status(slot->acpi_slot); @@ -265,66 +255,19 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) * @value: pointer to store status * * ACPI doesn't provide any formal means to access adapter status. - * Instead, we fake adapter status from _STA - * + * Instead, we fake adapter status from _STA. */ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_adapter_status(slot->acpi_slot); return 0; } - -/** - * get_address - get pci address of a slot - * @hotplug_slot: slot to get status - * @value: pointer to struct pci_busdev (seg, bus, dev) - */ -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) -{ - struct slot *slot = hotplug_slot->private; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_address(slot->acpi_slot); - - return 0; -} - -static int __init init_acpi(void) -{ - int retval; - - /* initialize internal data structure etc. */ - retval = acpiphp_glue_init(); - - /* read initial number of slots */ - if (!retval) { - num_slots = acpiphp_get_num_slots(); - if (num_slots == 0) - retval = -ENODEV; - } - - return retval; -} - - -/** - * make_slot_name - make a slot name that appears in pcihpfs - * @slot: slot to name - * - */ -static void make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u", - slot->acpi_slot->sun); -} - /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -333,76 +276,56 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } -/** - * init_slots - initialize 'struct slot' structures for each slot - * - */ -static int __init init_slots(void) +/* callback routine to initialize 'struct slot' for each slot */ +int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, + unsigned int sun) { struct slot *slot; int retval = -ENOMEM; - int i; - - for (i = 0; i < num_slots; ++i) { - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) - goto error; - memset(slot, 0, sizeof(struct slot)); - - slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) - goto error_slot; - memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - - slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->hotplug_slot->info) - goto error_hpslot; - memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); - - slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!slot->hotplug_slot->name) - goto error_info; - - slot->number = i; - - slot->hotplug_slot->private = slot; - slot->hotplug_slot->release = &release_slot; - slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; - - slot->acpi_slot = get_slot_from_id(i); - slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = 0; - slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); - slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); - slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; - slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; - - make_slot_name(slot); - - retval = pci_hp_register(slot->hotplug_slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - goto error_name; - } - - /* add slot to our internal list */ - list_add(&slot->slot_list, &slot_list); - info("Slot [%s] registered\n", slot->hotplug_slot->name); + char name[SLOT_NAME_SIZE]; + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + goto error; + + slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) + goto error_slot; + + slot->hotplug_slot->info = &slot->info; + + slot->hotplug_slot->private = slot; + slot->hotplug_slot->release = &release_slot; + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + + slot->acpi_slot = acpiphp_slot; + slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = 0; + slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); + slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); + + acpiphp_slot->slot = slot; + slot->sun = sun; + snprintf(name, SLOT_NAME_SIZE, "%u", sun); + + retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus, + acpiphp_slot->device, name); + if (retval == -EBUSY) + goto error_hpslot; + if (retval) { + pr_err("pci_hp_register failed with error %d\n", retval); + goto error_hpslot; } + pr_info("Slot [%s] registered\n", slot_name(slot)); + return 0; -error_name: - kfree(slot->hotplug_slot->name); -error_info: - kfree(slot->hotplug_slot->info); error_hpslot: kfree(slot->hotplug_slot); error_slot: @@ -412,43 +335,22 @@ error: } -static void __exit cleanup_slots (void) -{ - struct list_head *tmp, *n; - struct slot *slot; - - list_for_each_safe (tmp, n, &slot_list) { - /* memory will be freed in release_slot callback */ - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - } -} - - -static int __init acpiphp_init(void) +void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) { - int retval; - - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + struct slot *slot = acpiphp_slot->slot; + int retval = 0; - acpiphp_debug = debug; + pr_info("Slot [%s] unregistered\n", slot_name(slot)); - /* read all the ACPI info from the system */ - retval = init_acpi(); + retval = pci_hp_deregister(slot->hotplug_slot); if (retval) - return retval; - - return init_slots(); + pr_err("pci_hp_deregister failed with error %d\n", retval); } -static void __exit acpiphp_exit(void) +void __init acpiphp_init(void) { - cleanup_slots(); - /* deallocate internal data structures etc. */ - acpiphp_glue_exit(); + pr_info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", + acpiphp_disabled ? ", disabled by user; please report a bug" + : ""); } - -module_init(acpiphp_init); -module_exit(acpiphp_exit); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8e21f6ab89a..602d153c705 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -26,859 +26,598 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to <t-kochi@bq.jp.nec.com> + * Send feedback to <kristen.c.accardi@intel.com> * */ /* * Lifetime rules for pci_dev: - * - The one in acpiphp_func has its refcount elevated by pci_get_slot() - * when the driver is loaded or when an insertion event occurs. It loses - * a refcount when its ejected or the driver unloads. * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() * when the bridge is scanned and it loses a refcount when the bridge * is removed. + * - When a P2P bridge is present, we elevate the refcount on the subordinate + * bus. It loses the refcount when the the driver unloads. */ -#include <linux/init.h> +#define pr_fmt(fmt) "acpiphp_glue: " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> -#include <linux/smp_lock.h> -#include <asm/semaphore.h> +#include <linux/pci_hotplug.h> +#include <linux/pci-acpi.h> +#include <linux/pm_runtime.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/acpi.h> #include "../pci.h" -#include "pci_hotplug.h" #include "acpiphp.h" static LIST_HEAD(bridge_list); +static DEFINE_MUTEX(bridge_mutex); -#define MY_NAME "acpiphp_glue" - -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); -static void handle_hotplug_event_func (acpi_handle, u32, void *); +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type); +static void acpiphp_post_dock_fixup(struct acpi_device *adev); static void acpiphp_sanitize_bus(struct pci_bus *bus); -static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); - - -/* - * initialization & terminatation routines - */ +static void acpiphp_set_hpp_values(struct pci_bus *bus); +static void hotplug_event(u32 type, struct acpiphp_context *context); +static void free_bridge(struct kref *kref); /** - * is_ejectable - determine if a slot is ejectable - * @handle: handle to acpi namespace - * - * Ejectable slot should satisfy at least these conditions: - * - * 1. has _ADR method - * 2. has _EJ0 method - * - * optionally - * - * 1. has _STA method - * 2. has _PS0 method - * 3. has _PS3 method - * 4. .. + * acpiphp_init_context - Create hotplug context and grab a reference to it. + * @adev: ACPI device object to create the context for. * + * Call under acpi_hp_context_lock. */ -static int is_ejectable(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { - acpi_status status; - acpi_handle tmp; + struct acpiphp_context *context; - status = acpi_get_handle(handle, "_ADR", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return NULL; - return 1; + context->refcount = 1; + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL, + acpiphp_post_dock_fixup); + return context; } - -/* callback routine to check the existence of ejectable slots */ -static acpi_status -is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) +/** + * acpiphp_get_context - Get hotplug context and grab a reference to it. + * @adev: ACPI device object to get the context for. + * + * Call under acpi_hp_context_lock. + */ +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - int *count = (int *)context; + struct acpiphp_context *context; - if (is_ejectable(handle)) { - (*count)++; - /* only one ejectable slot is enough */ - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} + if (!adev->hp) + return NULL; + context = to_acpiphp_context(adev->hp); + context->refcount++; + return context; +} -/* callback routine to register each ACPI PCI slot object */ -static acpi_status -register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) +/** + * acpiphp_put_context - Drop a reference to ACPI hotplug context. + * @context: ACPI hotplug context to drop a reference to. + * + * The context object is removed if there are no more references to it. + * + * Call under acpi_hp_context_lock. + */ +static void acpiphp_put_context(struct acpiphp_context *context) { - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; - struct acpiphp_slot *slot; - struct acpiphp_func *newfunc; - acpi_handle tmp; - acpi_status status = AE_OK; - unsigned long adr, sun; - int device, function; - static int num_slots = 0; /* XXX if we support I/O node hotplug... */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); - - if (ACPI_FAILURE(status)) - return AE_OK; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - - if (ACPI_FAILURE(status)) - return AE_OK; - - device = (adr >> 16) & 0xffff; - function = adr & 0xffff; - - newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); - if (!newfunc) - return AE_NO_MEMORY; - memset(newfunc, 0, sizeof(struct acpiphp_func)); - - INIT_LIST_HEAD(&newfunc->sibling); - newfunc->handle = handle; - newfunc->function = function; - newfunc->flags = FUNC_HAS_EJ0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) - newfunc->flags |= FUNC_HAS_STA; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) - newfunc->flags |= FUNC_HAS_PS0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) - newfunc->flags |= FUNC_HAS_PS3; - - status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) - sun = -1; - - /* search for objects that share the same slot */ - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->device == device) { - if (slot->sun != sun) - warn("sibling found, but _SUN doesn't match!\n"); - break; - } - - if (!slot) { - slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); - if (!slot) { - kfree(newfunc); - return AE_NO_MEMORY; - } - - memset(slot, 0, sizeof(struct acpiphp_slot)); - slot->bridge = bridge; - slot->id = num_slots++; - slot->device = device; - slot->sun = sun; - INIT_LIST_HEAD(&slot->funcs); - init_MUTEX(&slot->crit_sect); - - slot->next = bridge->slots; - bridge->slots = slot; - - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(bridge->pci_bus), - bridge->pci_bus->number, slot->device); - } - - newfunc->slot = slot; - list_add_tail(&newfunc->sibling, &slot->funcs); - - /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_get_slot(bridge->pci_bus, - PCI_DEVFN(device, function)); - if (newfunc->pci_dev) { - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); - } - - /* install notify handler */ - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - return status; - } + if (--context->refcount) + return; - return AE_OK; + WARN_ON(context->bridge); + context->hp.self->hp = NULL; + kfree(context); } - -/* see if it's worth looking at this bridge */ -static int detect_ejectable_slots(acpi_handle *bridge_handle) +static inline void get_bridge(struct acpiphp_bridge *bridge) { - acpi_status status; - int count; - - count = 0; - - /* only check slots defined directly below bridge object */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, - is_ejectable_slot, (void *)&count, NULL); - - return count; + kref_get(&bridge->ref); } - -/* decode ACPI 2.0 _HPP hot plug parameters */ -static void decode_hpp(struct acpiphp_bridge *bridge) +static inline void put_bridge(struct acpiphp_bridge *bridge) { - acpi_status status; - struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL}; - union acpi_object *package; - int i; - - /* default numbers */ - bridge->hpp.cache_line_size = 0x10; - bridge->hpp.latency_timer = 0x40; - bridge->hpp.enable_SERR = 0; - bridge->hpp.enable_PERR = 0; - - status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); - - if (ACPI_FAILURE(status)) { - dbg("_HPP evaluation failed\n"); - return; - } - - package = (union acpi_object *) buffer.pointer; - - if (!package || package->type != ACPI_TYPE_PACKAGE || - package->package.count != 4 || !package->package.elements) { - err("invalid _HPP object; ignoring\n"); - goto err_exit; - } - - for (i = 0; i < 4; i++) { - if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { - err("invalid _HPP parameter type; ignoring\n"); - goto err_exit; - } - } - - bridge->hpp.cache_line_size = package->package.elements[0].integer.value; - bridge->hpp.latency_timer = package->package.elements[1].integer.value; - bridge->hpp.enable_SERR = package->package.elements[2].integer.value; - bridge->hpp.enable_PERR = package->package.elements[3].integer.value; - - dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", - bridge->hpp.cache_line_size, - bridge->hpp.latency_timer, - bridge->hpp.enable_SERR, - bridge->hpp.enable_PERR); - - bridge->flags |= BRIDGE_HAS_HPP; - - err_exit: - kfree(buffer.pointer); + kref_put(&bridge->ref, free_bridge); } - -/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ -static void init_bridge_misc(struct acpiphp_bridge *bridge) +static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev) { - acpi_status status; - - /* decode ACPI 2.0 _HPP (hot plug parameters) */ - decode_hpp(bridge); + struct acpiphp_context *context; - /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, - register_slot, bridge, NULL); - - /* install notify handler */ - if (bridge->type != BRIDGE_TYPE_HOST) { - status = acpi_install_notify_handler(bridge->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } + acpi_lock_hp_context(); + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { + acpi_unlock_hp_context(); + return NULL; } - - list_add(&bridge->list, &bridge_list); + get_bridge(context->func.parent); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return context; } - -/* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) +static void acpiphp_let_context_go(struct acpiphp_context *context) { - struct acpiphp_bridge *bridge; - - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) - return; - - memset(bridge, 0, sizeof(struct acpiphp_bridge)); - - bridge->type = BRIDGE_TYPE_HOST; - bridge->handle = handle; - - bridge->pci_bus = pci_bus; - - spin_lock_init(&bridge->res_lock); - - init_bridge_misc(bridge); + put_bridge(context->func.parent); } - -/* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) +static void free_bridge(struct kref *kref) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot, *next; + struct acpiphp_func *func, *tmp; - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) { - err("out of memory\n"); - return; - } + acpi_lock_hp_context(); - memset(bridge, 0, sizeof(struct acpiphp_bridge)); + bridge = container_of(kref, struct acpiphp_bridge, ref); - bridge->type = BRIDGE_TYPE_P2P; - bridge->handle = handle; + list_for_each_entry_safe(slot, next, &bridge->slots, node) { + list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) + acpiphp_put_context(func_to_context(func)); - bridge->pci_dev = pci_dev_get(pci_dev); - bridge->pci_bus = pci_dev->subordinate; - if (!bridge->pci_bus) { - err("This is not a PCI-to-PCI bridge!\n"); - goto err; + kfree(slot); } - spin_lock_init(&bridge->res_lock); + context = bridge->context; + /* Root bridges will not have hotplug context. */ + if (context) { + /* Release the reference taken by acpiphp_enumerate_slots(). */ + put_bridge(context->func.parent); + context->bridge = NULL; + acpiphp_put_context(context); + } - init_bridge_misc(bridge); - return; - err: - pci_dev_put(pci_dev); + put_device(&bridge->pci_bus->dev); + pci_dev_put(bridge->pci_dev); kfree(bridge); - return; -} + acpi_unlock_hp_context(); +} -/* callback routine to find P2P bridges */ -static acpi_status -find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) +/** + * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices. + * @adev: ACPI device object corresponding to a PCI device. + * + * TBD - figure out a way to only call fixups for systems that require them. + */ +static void acpiphp_post_dock_fixup(struct acpi_device *adev) { - acpi_status status; - acpi_handle dummy_handle; - unsigned long tmp; - int device, function; - struct pci_dev *dev; - struct pci_bus *pci_bus = context; - - status = acpi_get_handle(handle, "_ADR", &dummy_handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* continue */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _ADR evaluation failure\n", __FUNCTION__); - return AE_OK; - } - - device = (tmp >> 16) & 0xffff; - function = tmp & 0xffff; + struct acpiphp_context *context = acpiphp_grab_context(adev); + struct pci_bus *bus; + u32 buses; - dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); + if (!context) + return; - if (!dev || !dev->subordinate) + bus = context->func.slot->bus; + if (!bus->self) goto out; - /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); - add_p2p_bridge(handle, dev); + /* fixup bad _DCK function that rewrites + * secondary bridge on slot + */ + pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses); + + if (((buses >> 8) & 0xff) != bus->busn_res.start) { + buses = (buses & 0xff000000) + | ((unsigned int)(bus->primary) << 0) + | ((unsigned int)(bus->busn_res.start) << 8) + | ((unsigned int)(bus->busn_res.end) << 16); + pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } out: - pci_dev_put(dev); - return AE_OK; + acpiphp_let_context_go(context); } - -/* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridge(acpi_handle handle) +/* Check whether the PCI device is managed by native PCIe hotplug driver */ +static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) { - acpi_status status; - unsigned long tmp; - int seg, bus; - acpi_handle dummy_handle; - struct pci_bus *pci_bus; - - /* if the bridge doesn't have _STA, we assume it is always there */ - status = acpi_get_handle(handle, "_STA", &dummy_handle); - if (ACPI_SUCCESS(status)) { - status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _STA evaluation failure\n", __FUNCTION__); - return 0; - } - if ((tmp & ACPI_STA_FUNCTIONING) == 0) - /* don't register this object */ - return 0; - } - - /* get PCI segment number */ - status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); - - seg = ACPI_SUCCESS(status) ? tmp : 0; + u32 reg32; + acpi_handle tmp; + struct acpi_pci_root *root; + + /* Check whether the PCIe port supports native PCIe hotplug */ + if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, ®32)) + return false; + if (!(reg32 & PCI_EXP_SLTCAP_HPC)) + return false; + + /* + * Check whether native PCIe hotplug has been enabled for + * this PCIe hierarchy. + */ + tmp = acpi_find_root_bridge_handle(pdev); + if (!tmp) + return false; + root = acpi_pci_find_root(tmp); + if (!root) + return false; + if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) + return false; + + return true; +} - /* get PCI bus number */ - status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); +/** + * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. + * @handle: ACPI handle of the object to add a context to. + * @lvl: Not used. + * @data: The object's parent ACPIPHP bridge. + * @rv: Not used. + */ +static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, + void **rv) +{ + struct acpiphp_bridge *bridge = data; + struct acpiphp_context *context; + struct acpi_device *adev; + struct acpiphp_slot *slot; + struct acpiphp_func *newfunc; + acpi_status status = AE_OK; + unsigned long long adr; + int device, function; + struct pci_bus *pbus = bridge->pci_bus; + struct pci_dev *pdev = bridge->pci_dev; + u32 val; - if (ACPI_SUCCESS(status)) { - bus = tmp; - } else { - warn("can't get bus number, assuming 0\n"); - bus = 0; + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + acpi_handle_warn(handle, + "can't evaluate _ADR (%#x)\n", status); + return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; - pci_bus = pci_find_bus(seg, bus); - if (!pci_bus) { - err("Can't find bus %04x:%02x\n", seg, bus); - return 0; - } + device = (adr >> 16) & 0xffff; + function = adr & 0xffff; - /* check if this bridge has ejectable slots */ - 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; + acpi_lock_hp_context(); + context = acpiphp_init_context(adev); + if (!context) { + acpi_unlock_hp_context(); + acpi_handle_err(handle, "No hotplug context\n"); + return AE_NOT_EXIST; } + newfunc = &context->func; + newfunc->function = function; + newfunc->parent = bridge; + acpi_unlock_hp_context(); - /* search P2P bridges under this host bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, pci_bus, NULL); + /* + * If this is a dock device, its _EJ0 should be executed by the dock + * notify handler after calling _DCK. + */ + if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0")) + newfunc->flags = FUNC_HAS_EJ0; - if (ACPI_FAILURE(status)) - warn("find_p2p_bridge faied (error code = 0x%x)\n",status); + if (acpi_has_method(handle, "_STA")) + newfunc->flags |= FUNC_HAS_STA; - return 0; -} + /* search for objects that share the same slot */ + list_for_each_entry(slot, &bridge->slots, node) + if (slot->device == device) + goto slot_found; -static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) -{ - struct list_head *head; - list_for_each(head, &bridge_list) { - struct acpiphp_bridge *bridge = list_entry(head, - struct acpiphp_bridge, list); - if (bridge->handle == handle) - return bridge; + slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); + if (!slot) { + acpi_lock_hp_context(); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return AE_NO_MEMORY; } - return NULL; -} + slot->bus = bridge->pci_bus; + slot->device = device; + INIT_LIST_HEAD(&slot->funcs); -static void cleanup_bridge(struct acpiphp_bridge *bridge) -{ - struct list_head *list, *tmp; - struct acpiphp_slot *slot; - acpi_status status; - acpi_handle handle = bridge->handle; - - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - slot = bridge->slots; - while (slot) { - struct acpiphp_slot *next = slot->next; - list_for_each_safe (list, tmp, &slot->funcs) { - struct acpiphp_func *func; - func = list_entry(list, struct acpiphp_func, sibling); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - pci_dev_put(func->pci_dev); - list_del(list); - kfree(func); + list_add_tail(&slot->node, &bridge->slots); + + /* + * Expose slots to user space for functions that have _EJ0 or _RMV or + * are located in dock stations. Do not expose them for devices handled + * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to + * expose slots to user space in those cases. + */ + if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev)) + && !(pdev && device_is_managed_by_native_pciehp(pdev))) { + unsigned long long sun; + int retval; + + bridge->nr_slots++; + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + sun = bridge->nr_slots; + + pr_debug("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", + sun, pci_domain_nr(pbus), pbus->number, device); + + retval = acpiphp_register_hotplug_slot(slot, sun); + if (retval) { + slot->slot = NULL; + bridge->nr_slots--; + if (retval == -EBUSY) + pr_warn("Slot %llu already registered by another hotplug driver\n", sun); + else + pr_warn("acpiphp_register_hotplug_slot failed (err code = 0x%x)\n", retval); } - kfree(slot); - slot = next; + /* Even if the slot registration fails, we can still use it. */ } - pci_dev_put(bridge->pci_dev); - list_del(&bridge->list); - kfree(bridge); -} + slot_found: + newfunc->slot = slot; + list_add_tail(&newfunc->sibling, &slot->funcs); -static acpi_status -cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge; + if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), + &val, 60*1000)) + slot->flags |= SLOT_ENABLED; - if (!(bridge = acpiphp_handle_to_bridge(handle))) - return AE_OK; - cleanup_bridge(bridge); return AE_OK; } -static void remove_bridge(acpi_handle handle) +static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) { - struct acpiphp_bridge *bridge; + struct acpiphp_bridge *bridge = NULL; - bridge = acpiphp_handle_to_bridge(handle); - if (bridge) { - cleanup_bridge(bridge); - } else { - /* clean-up p2p bridges under this host bridge */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - (u32)1, cleanup_p2p_bridge, NULL, NULL); + acpi_lock_hp_context(); + if (adev->hp) { + bridge = to_acpiphp_root_context(adev->hp)->root_bridge; + if (bridge) + get_bridge(bridge); } + acpi_unlock_hp_context(); + return bridge; } -static struct pci_dev * get_apic_pci_info(acpi_handle handle) +static void cleanup_bridge(struct acpiphp_bridge *bridge) { - struct acpi_pci_id id; - struct pci_bus *bus; - struct pci_dev *dev; - - if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) - return NULL; - - bus = pci_find_bus(id.segment, id.bus); - if (!bus) - return NULL; + struct acpiphp_slot *slot; + struct acpiphp_func *func; - dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); - if (!dev) - return NULL; + list_for_each_entry(slot, &bridge->slots, node) { + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); - if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && - (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) - { - pci_dev_put(dev); - return NULL; + acpi_lock_hp_context(); + adev->hp->notify = NULL; + adev->hp->fixup = NULL; + acpi_unlock_hp_context(); + } + slot->flags |= SLOT_IS_GOING_AWAY; + if (slot->slot) + acpiphp_unregister_hotplug_slot(slot); } - return dev; + mutex_lock(&bridge_mutex); + list_del(&bridge->list); + mutex_unlock(&bridge_mutex); + + acpi_lock_hp_context(); + bridge->is_going_away = true; + acpi_unlock_hp_context(); } -static int get_gsi_base(acpi_handle handle, u32 *gsi_base) +/** + * acpiphp_max_busnr - return the highest reserved bus number under the given bus. + * @bus: bus to start search with + */ +static unsigned char acpiphp_max_busnr(struct pci_bus *bus) { - acpi_status status; - int result = -1; - unsigned long gsb; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; - void *table; - - status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); - if (ACPI_SUCCESS(status)) { - *gsi_base = (u32)gsb; - return 0; + struct pci_bus *tmp; + unsigned char max, n; + + /* + * pci_bus_max_busnr will return the highest + * reserved busnr for all these children. + * that is equivalent to the bus->subordinate + * value. We don't want to use the parent's + * bus->subordinate value because it could have + * padding in it. + */ + max = bus->busn_res.start; + + list_for_each_entry(tmp, &bus->children, node) { + n = pci_bus_max_busnr(tmp); + if (n > max) + max = n; } - - status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); - if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) - return -1; - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER) - goto out; - - table = obj->buffer.pointer; - switch (((acpi_table_entry_header *)table)->type) { - case ACPI_MADT_IOSAPIC: - *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; - result = 0; - break; - case ACPI_MADT_IOAPIC: - *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; - result = 0; - break; - default: - break; - } - out: - acpi_os_free(buffer.pointer); - return result; + return max; } -static acpi_status -ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) +static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { - acpi_status status; - unsigned long sta; - acpi_handle tmp; - struct pci_dev *pdev; - u32 gsi_base; - u64 phys_addr; - - /* Evaluate _STA if present */ - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) - return AE_CTRL_DEPTH; - - /* Scan only PCI bus scope */ - status = acpi_get_handle(handle, "_HID", &tmp); - if (ACPI_SUCCESS(status)) - return AE_CTRL_DEPTH; - - if (get_gsi_base(handle, &gsi_base)) - return AE_OK; - - pdev = get_apic_pci_info(handle); - if (!pdev) - return AE_OK; - - if (pci_enable_device(pdev)) { - pci_dev_put(pdev); - return AE_OK; - } - - pci_set_master(pdev); - - if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { - pci_disable_device(pdev); - pci_dev_put(pdev); - return AE_OK; - } + struct acpiphp_func *func; + union acpi_object params[2]; + struct acpi_object_list arg_list; - phys_addr = pci_resource_start(pdev, 0); - if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { - pci_release_region(pdev, 0); - pci_disable_device(pdev); - pci_dev_put(pdev); - return AE_OK; + list_for_each_entry(func, &slot->funcs, sibling) { + arg_list.count = 2; + arg_list.pointer = params; + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = 1; + /* _REG is optional, we don't care about if there is failure */ + acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list, + NULL); } - - return AE_OK; -} - -static int acpiphp_configure_ioapics(acpi_handle handle) -{ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, ioapic_add, NULL, NULL); - return 0; } -static int power_on_slot(struct acpiphp_slot *slot) +static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) { - acpi_status status; struct acpiphp_func *func; - struct list_head *l; - int retval = 0; - - /* if already enabled, just skip */ - if (slot->flags & SLOT_POWEREDON) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0\n", __FUNCTION__); - status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } else - break; - } - } - /* TBD: evaluate _STA to check if the slot is enabled */ - - slot->flags |= SLOT_POWEREDON; + /* quirk, or pcie could set it already */ + if (dev->is_hotplug_bridge) + return; - err_exit: - return retval; + list_for_each_entry(func, &slot->funcs, sibling) { + if (PCI_FUNC(dev->devfn) == func->function) { + dev->is_hotplug_bridge = 1; + break; + } + } } - -static int power_off_slot(struct acpiphp_slot *slot) +static int acpiphp_rescan_slot(struct acpiphp_slot *slot) { - acpi_status status; struct acpiphp_func *func; - struct list_head *l; - - int retval = 0; - /* if already disabled, just skip */ - if ((slot->flags & SLOT_POWEREDON) == 0) - goto err_exit; + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS3 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } else - break; - } + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); } - - /* TBD: evaluate _STA to check if the slot is disabled */ - - slot->flags &= (~SLOT_POWEREDON); - - err_exit: - return retval; + return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } - /** - * enable_device - enable, configure a slot + * enable_slot - enable, configure a slot * @slot: slot to be enabled * * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. - * */ -static int enable_device(struct acpiphp_slot *slot) +static void enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; - struct pci_bus *bus = slot->bridge->pci_bus; - struct list_head *l; + struct pci_bus *bus = slot->bus; struct acpiphp_func *func; - int retval = 0; - int num, max, pass; - - if (slot->flags & SLOT_ENABLED) - goto err_exit; - - /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); - if (dev) { - /* This case shouldn't happen */ - err("pci_dev structure already exists.\n"); - pci_dev_put(dev); - retval = -1; - goto err_exit; - } + int max, pass; + LIST_HEAD(add_list); - num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); - if (num == 0) { - err("No new device found\n"); - retval = -1; - goto err_exit; - } - - max = bus->secondary; + acpiphp_rescan_slot(slot); + max = acpiphp_max_busnr(bus); for (pass = 0; pass < 2; pass++) { list_for_each_entry(dev, &bus->devices, bus_list) { if (PCI_SLOT(dev->devfn) != slot->device) continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + + if (pci_is_bridge(dev)) { max = pci_scan_bridge(bus, dev, max, pass); + if (pass && dev->subordinate) { + check_hotplug_bridge(slot, dev); + pcibios_resource_survey_bus(dev->subordinate); + __pci_bus_size_bridges(dev->subordinate, + &add_list); + } + } } } + __pci_bus_assign_resources(bus, &add_list, NULL); - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); - pci_enable_bridges(bus); - pci_bus_add_devices(bus); - acpiphp_set_hpp_values(DEVICE_ACPI_HANDLE(&bus->self->dev), bus); - acpiphp_configure_ioapics(DEVICE_ACPI_HANDLE(&bus->self->dev)); - - /* associate pci_dev to our representation */ - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, - func->function)); + acpiphp_set_hpp_values(bus); + acpiphp_set_acpi_region(slot); + + list_for_each_entry(dev, &bus->devices, bus_list) { + /* Assume that newly added devices are powered on already. */ + if (!dev->is_added) + dev->current_state = PCI_D0; } - slot->flags |= SLOT_ENABLED; + pci_bus_add_devices(bus); - err_exit: - return retval; + slot->flags |= SLOT_ENABLED; + list_for_each_entry(func, &slot->funcs, sibling) { + dev = pci_get_slot(bus, PCI_DEVFN(slot->device, + func->function)); + if (!dev) { + /* Do not set SLOT_ENABLED flag if some funcs + are not added. */ + slot->flags &= (~SLOT_ENABLED); + continue; + } + } } - /** - * disable_device - disable a slot + * disable_slot - disable a slot + * @slot: ACPI PHP slot */ -static int disable_device(struct acpiphp_slot *slot) +static void disable_slot(struct acpiphp_slot *slot) { - int retval = 0; + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *prev; struct acpiphp_func *func; - struct list_head *l; - - /* is this slot already disabled? */ - if (!(slot->flags & SLOT_ENABLED)) - goto err_exit; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (!func->pci_dev) - continue; + /* + * enable_slot() enumerates all functions in this device via + * pci_scan_slot(), whether they have associated ACPI hotplug + * methods (_EJ0, etc.) or not. Therefore, we remove all functions + * here. + */ + list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); - pci_remove_bus_device(func->pci_dev); - pci_dev_put(func->pci_dev); - func->pci_dev = NULL; - } + list_for_each_entry(func, &slot->funcs, sibling) + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); +} - err_exit: - return retval; +static bool acpiphp_no_hotplug(struct acpi_device *adev) +{ + return adev && adev->flags.no_hotplug; } +static bool slot_no_hotplug(struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + + list_for_each_entry(func, &slot->funcs, sibling) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) + return true; + + return false; +} /** * get_slot_status - get ACPI slot status + * @slot: ACPI PHP slot * - * if a slot has _STA for each function and if any one of them - * returned non-zero status, return it + * If a slot has _STA for each function and if any one of them + * returned non-zero status, return it. * - * if a slot doesn't have _STA and if any one of its functions' - * configuration space is configured, return 0x0f as a _STA + * If a slot doesn't have _STA and if any one of its functions' + * configuration space is configured, return 0x0f as a _STA. * - * otherwise return 0 + * Otherwise return 0. */ static unsigned int get_slot_status(struct acpiphp_slot *slot) { - acpi_status status; - unsigned long sta = 0; - u32 dvid; - struct list_head *l; + unsigned long long sta = 0; struct acpiphp_func *func; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - + list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { - status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); + acpi_status status; + + status = acpi_evaluate_integer(func_to_handle(func), + "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) break; } else { - pci_bus_read_config_dword(slot->bridge->pci_bus, + u32 dvid; + + pci_bus_read_config_dword(slot->bus, PCI_DEVFN(slot->device, func->function), PCI_VENDOR_ID, &dvid); @@ -892,142 +631,96 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } +static inline bool device_status_valid(unsigned int sta) +{ + /* + * ACPI spec says that _STA may return bit 0 clear with bit 3 set + * if the device is valid but does not require a device driver to be + * loaded (Section 6.3.7 of ACPI 5.0A). + */ + unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; + return (sta & mask) == mask; +} + /** - * acpiphp_eject_slot - physically eject the slot + * trim_stale_devices - remove PCI devices that are not responding. + * @dev: PCI device to start walking the hierarchy from. */ -static int acpiphp_eject_slot(struct acpiphp_slot *slot) +static void trim_stale_devices(struct pci_dev *dev) { - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - /* We don't want to call _EJ0 on non-existing functions. */ - if ((func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - return -1; - } else - break; - } + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); + struct pci_bus *bus = dev->subordinate; + bool alive = false; + + if (adev) { + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); + alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) + || acpiphp_no_hotplug(adev); + } + if (!alive) + alive = pci_device_is_present(dev); + + if (!alive) { + pci_stop_and_remove_bus_device(dev); + if (adev) + acpi_bus_trim(adev); + } else if (bus) { + struct pci_dev *child, *tmp; + + /* The device is a bridge. so check the bus below it. */ + pm_runtime_get_sync(&dev->dev); + list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) + trim_stale_devices(child); + + pm_runtime_put(&dev->dev); } - return 0; } /** * acpiphp_check_bridge - re-enumerate devices + * @bridge: where to begin re-enumeration * * Iterate over all slots under this bridge and make sure that if a * card is present they are enabled, and if not they are disabled. */ -static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) +static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) { struct acpiphp_slot *slot; - int retval = 0; - int enabled, disabled; - enabled = disabled = 0; + /* Bail out if the bridge is going away. */ + if (bridge->is_going_away) + return; - for (slot = bridge->slots; slot; slot = slot->next) { - unsigned int status = get_slot_status(slot); - if (slot->flags & SLOT_ENABLED) { - if (status == ACPI_STA_ALL) - continue; - retval = acpiphp_disable_slot(slot); - if (retval) { - err("Error occurred in disabling\n"); - goto err_exit; - } else { - acpiphp_eject_slot(slot); - } - disabled++; + list_for_each_entry(slot, &bridge->slots, node) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *tmp; + + if (slot_no_hotplug(slot)) { + ; /* do nothing */ + } else if (device_status_valid(get_slot_status(slot))) { + /* remove stale devices if any */ + list_for_each_entry_safe_reverse(dev, tmp, + &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + trim_stale_devices(dev); + + /* configure all functions */ + enable_slot(slot); } else { - if (status != ACPI_STA_ALL) - continue; - retval = acpiphp_enable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - goto err_exit; - } - enabled++; + disable_slot(slot); } } - - dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); - - err_exit: - return retval; } -static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) +static void acpiphp_set_hpp_values(struct pci_bus *bus) { - u16 pci_cmd, pci_bctl; - struct pci_dev *cdev; - - /* 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; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); - if (bridge->hpp.enable_SERR) - pci_cmd |= PCI_COMMAND_SERR; - else - pci_cmd &= ~PCI_COMMAND_SERR; - if (bridge->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 and child devices */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, - bridge->hpp.latency_timer); - pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); - if (bridge->hpp.enable_SERR) - pci_bctl |= PCI_BRIDGE_CTL_SERR; - else - pci_bctl &= ~PCI_BRIDGE_CTL_SERR; - if (bridge->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); - if (dev->subordinate) { - list_for_each_entry(cdev, &dev->subordinate->devices, - bus_list) - program_hpp(cdev, bridge); - } - } -} - -static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) -{ - struct acpiphp_bridge bridge; struct pci_dev *dev; - memset(&bridge, 0, sizeof(bridge)); - bridge.handle = handle; - decode_hpp(&bridge); list_for_each_entry(dev, &bus->devices, bus_list) - program_hpp(dev, &bridge); - + pci_configure_slot(dev); } /* @@ -1036,459 +729,328 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) */ static void acpiphp_sanitize_bus(struct pci_bus *bus) { - struct pci_dev *dev; + struct pci_dev *dev, *tmp; int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - list_for_each_entry(dev, &bus->devices, bus_list) { + list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && res->end) { /* Could not assign a required resources * for this device, remove it */ - pci_remove_bus_device(dev); + pci_stop_and_remove_bus_device(dev); break; } } } } -/* Program resources in newly inserted bridge */ -static int acpiphp_configure_bridge (acpi_handle handle) -{ - struct acpi_pci_id pci_id; - struct pci_bus *bus; - - if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { - err("cannot get PCI domain and bus number for bridge\n"); - return -EINVAL; - } - bus = pci_find_bus(pci_id.segment, pci_id.bus); - if (!bus) { - err("cannot find bus %d:%d\n", - pci_id.segment, pci_id.bus); - return -EINVAL; - } - - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); - acpiphp_sanitize_bus(bus); - acpiphp_set_hpp_values(handle, bus); - pci_enable_bridges(bus); - acpiphp_configure_ioapics(handle); - return 0; -} +/* + * ACPI event handlers + */ -static void handle_bridge_insertion(acpi_handle handle, u32 type) +void acpiphp_check_host_bridge(struct acpi_device *adev) { - struct acpi_device *device, *pdevice; - acpi_handle phandle; + struct acpiphp_bridge *bridge; - if ((type != ACPI_NOTIFY_BUS_CHECK) && - (type != ACPI_NOTIFY_DEVICE_CHECK)) { - err("unexpected notification type %d\n", type); - return; - } + bridge = acpiphp_dev_to_bridge(adev); + if (bridge) { + pci_lock_rescan_remove(); - acpi_get_parent(handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } - if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { - err("cannot add bridge to acpi list\n"); - return; - } - if (!acpiphp_configure_bridge(handle) && - !acpi_bus_start(device)) - add_bridge(handle); - else - err("cannot configure and start bridge\n"); + acpiphp_check_bridge(bridge); + pci_unlock_rescan_remove(); + put_bridge(bridge); + } } -/* - * ACPI event handlers - */ +static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * handles ACPI event notification on {host,p2p} bridges - * - */ -static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) +static void hotplug_event(u32 type, struct acpiphp_context *context) { + acpi_handle handle = context->hp.self->handle; + struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - struct acpi_device *device; - - if (acpi_bus_get_device(handle, &device)) { - /* This bridge must have just been physically inserted */ - handle_bridge_insertion(handle, type); - return; - } - bridge = acpiphp_handle_to_bridge(handle); - if (!bridge) { - err("cannot get bridge info\n"); - return; - } + acpi_lock_hp_context(); + bridge = context->bridge; + if (bridge) + get_bridge(bridge); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + acpi_unlock_hp_context(); + + pci_lock_rescan_remove(); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); + if (bridge) + acpiphp_check_bridge(bridge); + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) + enable_slot(slot); + break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); + if (bridge) { + acpiphp_check_bridge(bridge); + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { + /* + * Check if anything has changed in the slot and rescan + * from the parent if that's the case. + */ + if (acpiphp_rescan_slot(slot)) + acpiphp_check_bridge(func->parent); + } break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); + acpiphp_disable_and_eject_slot(slot); break; + } - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a frequency mismatch\n", objname); - break; + pci_unlock_rescan_remove(); + if (bridge) + put_bridge(bridge); +} - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a bus mode mismatch\n", objname); - break; +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type) +{ + struct acpiphp_context *context; - case ACPI_NOTIFY_POWER_FAULT: - printk(KERN_ERR "Device %s has suffered a power fault\n", - objname); - break; + context = acpiphp_grab_context(adev); + if (!context) + return -ENODATA; - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } + hotplug_event(type, context); + acpiphp_let_context_go(context); + return 0; } /** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_func structure - * - * handles ACPI event notification on slots + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. * + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) +void acpiphp_enumerate_slots(struct pci_bus *bus) { - struct acpiphp_func *func; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; + struct acpiphp_bridge *bridge; + struct acpi_device *adev; + acpi_handle handle; + acpi_status status; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + if (acpiphp_disabled) + return; - func = (struct acpiphp_func *)context; + adev = ACPI_COMPANION(bus->bridge); + if (!adev) + return; - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_enable_slot(func->slot); - break; + handle = adev->handle; + bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); + if (!bridge) { + acpi_handle_err(handle, "No memory for bridge object\n"); + return; + } - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check : re-enumerate from parent bus */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(func->slot->bridge); - break; + INIT_LIST_HEAD(&bridge->slots); + kref_init(&bridge->ref); + bridge->pci_dev = pci_dev_get(bus->self); + bridge->pci_bus = bus; - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); - break; + /* + * Grab a ref to the subordinate PCI bus in case the bus is + * removed via PCI core logical hotplug. The ref pins the bus + * (which we access during module unload). + */ + get_device(&bus->dev); - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); - break; + acpi_lock_hp_context(); + if (pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_root_context *root_context; - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -} + root_context = kzalloc(sizeof(*root_context), GFP_KERNEL); + if (!root_context) + goto err; -static int is_root_bridge(acpi_handle handle) -{ - acpi_status status; - struct acpi_device_info *info; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - int i; - - status = acpi_get_object_info(handle, &buffer); - if (ACPI_SUCCESS(status)) { - info = buffer.pointer; - if ((info->valid & ACPI_VALID_HID) && - !strcmp(PCI_ROOT_HID_STRING, - info->hardware_id.value)) { - acpi_os_free(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); - return 1; - } - } - } + root_context->root_bridge = bridge; + acpi_set_hp_context(adev, &root_context->hp, NULL, NULL, NULL); + } else { + struct acpiphp_context *context; + + /* + * This bridge should have been registered as a hotplug function + * under its parent, so the context should be there, unless the + * parent is going to be handled by pciehp, in which case this + * bridge is not interesting to us either. + */ + context = acpiphp_get_context(adev); + if (!context) + goto err; + + bridge->context = context; + context->bridge = bridge; + /* Get a reference to the parent bridge. */ + get_bridge(context->func.parent); } - return 0; -} + acpi_unlock_hp_context(); -static acpi_status -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; + /* Must be added to the list prior to calling acpiphp_add_context(). */ + mutex_lock(&bridge_mutex); + list_add(&bridge->list, &bridge_list); + mutex_unlock(&bridge_mutex); - if (is_root_bridge(handle)) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, NULL); - (*count)++; + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpiphp_add_context, NULL, bridge, NULL); + if (ACPI_FAILURE(status)) { + acpi_handle_err(handle, "failed to register slots\n"); + cleanup_bridge(bridge); + put_bridge(bridge); } - return AE_OK ; -} - -static struct acpi_pci_driver acpi_pci_hp_driver = { - .add = add_bridge, - .remove = remove_bridge, -}; - -/** - * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures - * - */ -int __init acpiphp_glue_init(void) -{ - int num = 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, &num, NULL); - - if (num <= 0) - return -1; - else - acpi_pci_register_driver(&acpi_pci_hp_driver); + return; - return 0; + err: + acpi_unlock_hp_context(); + put_device(&bus->dev); + pci_dev_put(bridge->pci_dev); + kfree(bridge); } - -/** - * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures - * - * This function frees all data allocated in acpiphp_glue_init() - */ -void __exit acpiphp_glue_exit(void) +void acpiphp_drop_bridge(struct acpiphp_bridge *bridge) { - acpi_pci_unregister_driver(&acpi_pci_hp_driver); + if (pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_root_context *root_context; + struct acpi_device *adev; + + acpi_lock_hp_context(); + adev = ACPI_COMPANION(bridge->pci_bus->bridge); + root_context = to_acpiphp_root_context(adev->hp); + adev->hp = NULL; + acpi_unlock_hp_context(); + kfree(root_context); + } + cleanup_bridge(bridge); + put_bridge(bridge); } - /** - * acpiphp_get_num_slots - count number of slots in a system + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. */ -int __init acpiphp_get_num_slots(void) +void acpiphp_remove_slots(struct pci_bus *bus) { - struct list_head *node; struct acpiphp_bridge *bridge; - int num_slots; - num_slots = 0; + if (acpiphp_disabled) + return; - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - dbg("Bus %04x:%02x has %d slot%s\n", - pci_domain_nr(bridge->pci_bus), - bridge->pci_bus->number, bridge->nr_slots, - bridge->nr_slots == 1 ? "" : "s"); - num_slots += bridge->nr_slots; - } + mutex_lock(&bridge_mutex); + list_for_each_entry(bridge, &bridge_list, list) + if (bridge->pci_bus == bus) { + mutex_unlock(&bridge_mutex); + acpiphp_drop_bridge(bridge); + return; + } - dbg("Total %d slots\n", num_slots); - return num_slots; + mutex_unlock(&bridge_mutex); } - -#if 0 /** - * acpiphp_for_each_slot - call function for each slot - * @fn: callback function - * @data: context to be passed to callback function - * + * acpiphp_enable_slot - power on slot + * @slot: ACPI PHP slot */ -static int acpiphp_for_each_slot(acpiphp_callback fn, void *data) +int acpiphp_enable_slot(struct acpiphp_slot *slot) { - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - int retval = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) { - retval = fn(slot, data); - if (!retval) - goto err_exit; - } - } + pci_lock_rescan_remove(); - err_exit: - return retval; -} -#endif + if (slot->flags & SLOT_IS_GOING_AWAY) + return -ENODEV; -/* search matching slot from id */ -struct acpiphp_slot *get_slot_from_id(int id) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->id == id) - return slot; - } + /* configure all functions */ + if (!(slot->flags & SLOT_ENABLED)) + enable_slot(slot); - /* should never happen! */ - err("%s: no object for id %d\n", __FUNCTION__, id); - WARN_ON(1); - return NULL; + pci_unlock_rescan_remove(); + return 0; } - /** - * acpiphp_enable_slot - power on slot + * acpiphp_disable_and_eject_slot - power off and eject slot + * @slot: ACPI PHP slot */ -int acpiphp_enable_slot(struct acpiphp_slot *slot) +static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) { - int retval; + struct acpiphp_func *func; - down(&slot->crit_sect); + if (slot->flags & SLOT_IS_GOING_AWAY) + return -ENODEV; - /* wake up all functions */ - retval = power_on_slot(slot); - if (retval) - goto err_exit; + /* unconfigure all functions */ + disable_slot(slot); + + list_for_each_entry(func, &slot->funcs, sibling) + if (func->flags & FUNC_HAS_EJ0) { + acpi_handle handle = func_to_handle(func); - if (get_slot_status(slot) == ACPI_STA_ALL) - /* configure all functions */ - retval = enable_device(slot); + if (ACPI_FAILURE(acpi_evaluate_ej0(handle))) + acpi_handle_err(handle, "_EJ0 failed\n"); - err_exit: - up(&slot->crit_sect); - return retval; + break; + } + + return 0; } -/** - * acpiphp_disable_slot - power off slot - */ int acpiphp_disable_slot(struct acpiphp_slot *slot) { - int retval = 0; - - down(&slot->crit_sect); - - /* unconfigure all functions */ - retval = disable_device(slot); - if (retval) - goto err_exit; - - /* power off all functions */ - retval = power_off_slot(slot); - if (retval) - goto err_exit; - - err_exit: - up(&slot->crit_sect); - return retval; + int ret; + + /* + * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in + * acpiphp_disable_and_eject_slot() will be synchronized properly. + */ + acpi_scan_lock_acquire(); + pci_lock_rescan_remove(); + ret = acpiphp_disable_and_eject_slot(slot); + pci_unlock_rescan_remove(); + acpi_scan_lock_release(); + return ret; } - /* * slot enabled: 1 * slot disabled: 0 */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - return (slot->flags & SLOT_POWEREDON); + return (slot->flags & SLOT_ENABLED); } - /* - * latch closed: 1 - * latch open: 0 + * latch open: 1 + * latch closed: 0 */ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; + return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); } - /* * adapter presence : 1 * absence : 0 */ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta == 0) ? 0 : 1; -} - - -/* - * pci address (seg/bus/dev) - */ -u32 acpiphp_get_address(struct acpiphp_slot *slot) -{ - u32 address; - struct pci_bus *pci_bus = slot->bridge->pci_bus; - - address = (pci_domain_nr(pci_bus) << 16) | - (pci_bus->number << 8) | - slot->device; - - return address; + return !!get_slot_status(slot); } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 7e7f913ba7b..8dcccffd6e2 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -25,46 +25,37 @@ * */ +#define pr_fmt(fmt) "acpiphp_ibm: " fmt + #include <linux/init.h> +#include <linux/slab.h> #include <linux/module.h> #include <linux/kernel.h> -#include <acpi/acpi_bus.h> #include <linux/sysfs.h> #include <linux/kobject.h> -#include <asm/uaccess.h> #include <linux/moduleparam.h> +#include <linux/pci.h> +#include <asm/uaccess.h> #include "acpiphp.h" -#include "pci_hotplug.h" +#include "../pci.h" #define DRIVER_VERSION "1.0.1" #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension" -static int debug; MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, " Debugging mode enabled or not"); -#define MY_NAME "acpiphp_ibm" - -#undef dbg -#define dbg(format, arg...) \ -do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## arg); \ -} while (0) #define FOUND_APCI 0x61504349 /* these are the names for the IBM ACPI pseudo-device */ #define IBM_HARDWARE_ID1 "IBM37D0" #define IBM_HARDWARE_ID2 "IBM37D4" -#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun) +#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun) /* union apci_descriptor - allows access to the * various device descriptors that are embedded in the @@ -106,8 +97,9 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status); static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status); static void ibm_handle_events(acpi_handle handle, u32 event, void *context); static int ibm_get_table_from_acpi(char **bufp); -static ssize_t ibm_read_apci_table(struct kobject *kobj, - char *buffer, loff_t pos, size_t size); +static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t pos, size_t size); static acpi_status __init ibm_find_acpi_device(acpi_handle handle, u32 lvl, void *context, void **rv); static int __init ibm_acpiphp_init(void); @@ -118,13 +110,12 @@ static struct notification ibm_note; static struct bin_attribute ibm_apci_table_attr = { .attr = { .name = "apci_table", - .owner = THIS_MODULE, .mode = S_IRUGO, }, .read = ibm_read_apci_table, .write = NULL, }; -static struct acpiphp_attention_info ibm_attention_info = +static struct acpiphp_attention_info ibm_attention_info = { .set_attn = ibm_set_attention_status, .get_attn = ibm_get_attention_status, @@ -135,11 +126,11 @@ static struct acpiphp_attention_info ibm_attention_info = * ibm_slot_from_id - workaround for bad ibm hardware * @id: the slot number that linux refers to the slot by * - * Description: this method returns the aCPI slot descriptor + * Description: This method returns the aCPI slot descriptor * corresponding to the Linux slot number. This descriptor * has info about the aPCI slot id and attention status. * This descriptor must be freed using kfree when done. - **/ + */ static union apci_descriptor *ibm_slot_from_id(int id) { int ind = 0, size; @@ -174,20 +165,20 @@ ibm_slot_done: * @slot: the hotplug_slot to work with * @status: what to set the LED to (0 or 1) * - * Description: this method is registered with the acpiphp module as a - * callback to do the device specific task of setting the LED status - **/ + * Description: This method is registered with the acpiphp module as a + * callback to do the device specific task of setting the LED status. + */ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status) { - union acpi_object args[2]; + union acpi_object args[2]; struct acpi_object_list params = { .pointer = args, .count = 2 }; - acpi_status stat; - unsigned long rc; + acpi_status stat; + unsigned long long rc; union apci_descriptor *ibm_slot; ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot)); - dbg("%s: set slot %d (%d) attention status to %d\n", __FUNCTION__, + pr_debug("%s: set slot %d (%d) attention status to %d\n", __func__, ibm_slot->slot.slot_num, ibm_slot->slot.slot_id, (status ? 1 : 0)); @@ -200,10 +191,10 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status) stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", ¶ms, &rc); if (ACPI_FAILURE(stat)) { - err("APLS evaluation failed: 0x%08x\n", stat); + pr_err("APLS evaluation failed: 0x%08x\n", stat); return -ENODEV; } else if (!rc) { - err("APLS method failed: 0x%08lx\n", rc); + pr_err("APLS method failed: 0x%08llx\n", rc); return -ERANGE; } return 0; @@ -214,13 +205,13 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status) * @slot: the hotplug_slot to work with * @status: returns what the LED is set to (0 or 1) * - * Description: this method is registered with the acpiphp module as a - * callback to do the device specific task of getting the LED status - * + * Description: This method is registered with the acpiphp module as a + * callback to do the device specific task of getting the LED status. + * * Because there is no direct method of getting the LED status directly * from an ACPI call, we read the aPCI table and parse out our * slot descriptor to read the status from that. - **/ + */ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) { union apci_descriptor *ibm_slot; @@ -232,7 +223,7 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) else *status = 0; - dbg("%s: get slot %d (%d) attention status is %d\n", __FUNCTION__, + pr_debug("%s: get slot %d (%d) attention status is %d\n", __func__, ibm_slot->slot.slot_num, ibm_slot->slot.slot_id, *status); @@ -246,8 +237,8 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) * @event: the event info (device specific) * @context: passed context (our notification struct) * - * Description: this method is registered as a callback with the ACPI - * subsystem it is called when this device has an event to notify the OS of + * Description: This method is registered as a callback with the ACPI + * subsystem it is called when this device has an event to notify the OS of. * * The events actually come from the device as two events that get * synthesized into one event with data by this function. The event @@ -257,18 +248,20 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status) * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will * only re-enable the interrupt that causes this event AFTER this method * has returned, thereby enforcing serial access for the notification struct. - **/ + */ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) { u8 detail = event & 0x0f; u8 subevent = event & 0xf0; struct notification *note = context; - dbg("%s: Received notification %02x\n", __FUNCTION__, event); + pr_debug("%s: Received notification %02x\n", __func__, event); if (subevent == 0x80) { - dbg("%s: generationg bus event\n", __FUNCTION__); - acpi_bus_generate_event(note->device, note->event, detail); + pr_debug("%s: generating bus event\n", __func__); + acpi_bus_generate_netlink_event(note->device->pnp.device_class, + dev_name(¬e->device->dev), + note->event, detail); } else note->event = event; } @@ -277,16 +270,16 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) * ibm_get_table_from_acpi - reads the APLS buffer from ACPI * @bufp: address to pointer to allocate for the table * - * Description: this method reads the APLS buffer in from ACPI and + * Description: This method reads the APLS buffer in from ACPI and * stores the "stripped" table into a single buffer - * it allocates and passes the address back in bufp + * it allocates and passes the address back in bufp. * * If NULL is passed in as buffer, this method only calculates * the size of the table and returns that without filling - * in the buffer + * in the buffer. * - * returns < 0 on error or the size of the table on success - **/ + * Returns < 0 on error or the size of the table on success. + */ static int ibm_get_table_from_acpi(char **bufp) { union acpi_object *package; @@ -297,21 +290,21 @@ static int ibm_get_table_from_acpi(char **bufp) status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer); if (ACPI_FAILURE(status)) { - err("%s: APCI evaluation failed\n", __FUNCTION__); + pr_err("%s: APCI evaluation failed\n", __func__); return -ENODEV; } package = (union acpi_object *) buffer.pointer; - if(!(package) || + if (!(package) || (package->type != ACPI_TYPE_PACKAGE) || !(package->package.elements)) { - err("%s: Invalid APCI object\n", __FUNCTION__); + pr_err("%s: Invalid APCI object\n", __func__); goto read_table_done; } for(size = 0, i = 0; i < package->package.count; i++) { if (package->package.elements[i].type != ACPI_TYPE_BUFFER) { - err("%s: Invalid APCI element %d\n", __FUNCTION__, i); + pr_err("%s: Invalid APCI element %d\n", __func__, i); goto read_table_done; } size += package->package.elements[i].buffer.length; @@ -320,13 +313,12 @@ static int ibm_get_table_from_acpi(char **bufp) if (bufp == NULL) goto read_table_done; - lbuf = kmalloc(size, GFP_KERNEL); - dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n", - __FUNCTION__, package->package.count, size, lbuf); + lbuf = kzalloc(size, GFP_KERNEL); + pr_debug("%s: element count: %i, ASL table size: %i, &table = 0x%p\n", + __func__, package->package.count, size, lbuf); if (lbuf) { *bufp = lbuf; - memset(lbuf, 0, size); } else { size = -ENOMEM; goto read_table_done; @@ -347,25 +339,28 @@ read_table_done: /** * ibm_read_apci_table - callback for the sysfs apci_table file + * @filp: the open sysfs file * @kobj: the kobject this binary attribute is a part of + * @bin_attr: struct bin_attribute for this file * @buffer: the kernel space buffer to fill * @pos: the offset into the file * @size: the number of bytes requested * - * Description: gets registered with sysfs as the reader callback - * to be executed when /sys/bus/pci/slots/apci_table gets read + * Description: Gets registered with sysfs as the reader callback + * to be executed when /sys/bus/pci/slots/apci_table gets read. * * Since we don't get notified on open and close for this file, * things get really tricky here... - * our solution is to only allow reading the table in all at once - **/ -static ssize_t ibm_read_apci_table(struct kobject *kobj, - char *buffer, loff_t pos, size_t size) + * our solution is to only allow reading the table in all at once. + */ +static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t pos, size_t size) { int bytes_read = -EINVAL; char *table = NULL; - - dbg("%s: pos = %d, size = %zd\n", __FUNCTION__, (int)pos, size); + + pr_debug("%s: pos = %d, size = %zd\n", __func__, (int)pos, size); if (pos == 0) { bytes_read = ibm_get_table_from_acpi(&table); @@ -383,42 +378,40 @@ static ssize_t ibm_read_apci_table(struct kobject *kobj, * @context: a pointer to our handle to fill when we find the device * @rv: a return value to fill if desired * - * Description: used as a callback when calling acpi_walk_namespace + * Description: Used as a callback when calling acpi_walk_namespace * to find our device. When this method returns non-zero - * acpi_walk_namespace quits its search and returns our value - **/ + * acpi_walk_namespace quits its search and returns our value. + */ static acpi_status __init ibm_find_acpi_device(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_handle *phandle = (acpi_handle *)context; - acpi_status status; - struct acpi_device_info info; - struct acpi_buffer info_buffer = { - .length = sizeof(struct acpi_device_info), - .pointer = &info, - }; - - status = acpi_get_object_info(handle, &info_buffer); + acpi_status status; + struct acpi_device_info *info; + int retval = 0; + + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) { - err("%s: Failed to get device information", __FUNCTION__); - return 0; + pr_err("%s: Failed to get device information status=0x%x\n", + __func__, status); + return retval; } - info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0'; - if(info.current_status && (info.valid & ACPI_VALID_HID) && - (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) || - !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) { - dbg("found hardware: %s, handle: %p\n", info.hardware_id.value, - handle); + if (info->current_status && (info->valid & ACPI_VALID_HID) && + (!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) || + !strcmp(info->hardware_id.string, IBM_HARDWARE_ID2))) { + pr_debug("found hardware: %s, handle: %p\n", + info->hardware_id.string, handle); *phandle = handle; /* returning non-zero causes the search to stop - * and returns this value to the caller of + * and returns this value to the caller of * acpi_walk_namespace, but it also causes some warnings * in the acpi debug code to print... */ - return FOUND_APCI; + retval = FOUND_APCI; } - return 0; + kfree(info); + return retval; } static int __init ibm_acpiphp_init(void) @@ -426,20 +419,20 @@ static int __init ibm_acpiphp_init(void) int retval = 0; acpi_status status; struct acpi_device *device; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + struct kobject *sysdir = &pci_slots_kset->kobj; - dbg("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ibm_find_acpi_device, + ACPI_UINT32_MAX, ibm_find_acpi_device, NULL, &ibm_acpi_handle, NULL) != FOUND_APCI) { - err("%s: acpi_walk_namespace failed\n", __FUNCTION__); + pr_err("%s: acpi_walk_namespace failed\n", __func__); retval = -ENODEV; goto init_return; } - dbg("%s: found IBM aPCI device\n", __FUNCTION__); + pr_debug("%s: found IBM aPCI device\n", __func__); if (acpi_bus_get_device(ibm_acpi_handle, &device)) { - err("%s: acpi_bus_get_device failed\n", __FUNCTION__); + pr_err("%s: acpi_bus_get_device failed\n", __func__); retval = -ENODEV; goto init_return; } @@ -449,14 +442,12 @@ static int __init ibm_acpiphp_init(void) } ibm_note.device = device; - status = acpi_install_notify_handler( - ibm_acpi_handle, - ACPI_DEVICE_NOTIFY, - ibm_handle_events, + status = acpi_install_notify_handler(ibm_acpi_handle, + ACPI_DEVICE_NOTIFY, ibm_handle_events, &ibm_note); if (ACPI_FAILURE(status)) { - err("%s: Failed to register notification handler\n", - __FUNCTION__); + pr_err("%s: Failed to register notification handler\n", + __func__); retval = -EBUSY; goto init_cleanup; } @@ -475,24 +466,21 @@ init_return: static void __exit ibm_acpiphp_exit(void) { acpi_status status; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; + struct kobject *sysdir = &pci_slots_kset->kobj; - dbg("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (acpiphp_unregister_attention(&ibm_attention_info)) - err("%s: attention info deregistration failed", __FUNCTION__); + pr_err("%s: attention info deregistration failed", __func__); - status = acpi_remove_notify_handler( + status = acpi_remove_notify_handler( ibm_acpi_handle, ACPI_DEVICE_NOTIFY, ibm_handle_events); - if (ACPI_FAILURE(status)) - err("%s: Notification handler removal failed\n", - __FUNCTION__); - // remove the /sys entries - if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr)) - err("%s: removal of sysfs file apci_table failed\n", - __FUNCTION__); + if (ACPI_FAILURE(status)) + pr_err("%s: Notification handler removal failed\n", __func__); + /* remove the /sys entries */ + sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr); } module_init(ibm_acpiphp_init); diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index d9769b30be9..6a0ddf75734 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -30,6 +30,7 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> /* PICMG 2.1 R2.0 HS CSR bits: */ #define HS_CSR_INS 0x0080 @@ -55,9 +56,9 @@ struct cpci_hp_controller_ops { int (*enable_irq) (void); int (*disable_irq) (void); int (*check_irq) (void *dev_id); - int (*hardware_test) (struct slot* slot, u32 value); - u8 (*get_power) (struct slot* slot); - int (*set_power) (struct slot* slot, int value); + int (*hardware_test) (struct slot *slot, u32 value); + u8 (*get_power) (struct slot *slot); + int (*set_power) (struct slot *slot, int value); }; struct cpci_hp_controller { @@ -69,28 +70,41 @@ struct cpci_hp_controller { struct cpci_hp_controller_ops *ops; }; -extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); -extern int cpci_hp_unregister_bus(struct pci_bus *bus); -extern int cpci_hp_start(void); -extern int cpci_hp_stop(void); +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + +int cpci_hp_register_controller(struct cpci_hp_controller *controller); +int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); +int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); +int cpci_hp_unregister_bus(struct pci_bus *bus); +int cpci_hp_start(void); +int cpci_hp_stop(void); /* * Internal function prototypes, these functions should not be used by * board/chassis drivers. */ -extern u8 cpci_get_attention_status(struct slot *slot); -extern u8 cpci_get_latch_status(struct slot *slot); -extern u8 cpci_get_adapter_status(struct slot *slot); -extern u16 cpci_get_hs_csr(struct slot * slot); -extern int cpci_set_attention_status(struct slot *slot, int status); -extern int cpci_check_and_clear_ins(struct slot * slot); -extern int cpci_check_ext(struct slot * slot); -extern int cpci_clear_ext(struct slot * slot); -extern int cpci_led_on(struct slot * slot); -extern int cpci_led_off(struct slot * slot); -extern int cpci_configure_slot(struct slot *slot); -extern int cpci_unconfigure_slot(struct slot *slot); +u8 cpci_get_attention_status(struct slot *slot); +u8 cpci_get_latch_status(struct slot *slot); +u8 cpci_get_adapter_status(struct slot *slot); +u16 cpci_get_hs_csr(struct slot *slot); +int cpci_set_attention_status(struct slot *slot, int status); +int cpci_check_and_clear_ins(struct slot *slot); +int cpci_check_ext(struct slot *slot); +int cpci_clear_ext(struct slot *slot); +int cpci_led_on(struct slot *slot); +int cpci_led_off(struct slot *slot); +int cpci_configure_slot(struct slot *slot); +int cpci_unconfigure_slot(struct slot *slot); + +#ifdef CONFIG_HOTPLUG_PCI_CPCI +int cpci_hotplug_init(int debug); +void cpci_hotplug_exit(void); +#else +static inline int cpci_hotplug_init(int debug) { return 0; } +static inline void cpci_hotplug_exit(void) { } +#endif #endif /* _CPCI_HOTPLUG_H */ diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 30af105271a..e09cf7827d6 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -25,17 +25,16 @@ * Send feedback to <scottm@somanetworks.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/smp_lock.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <linux/delay.h> -#include "pci_hotplug.h" +#include <linux/kthread.h> #include "cpci_hotplug.h" #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" @@ -47,7 +46,7 @@ do { \ if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ + MY_NAME , ## arg); \ } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) @@ -60,20 +59,18 @@ static int slots; static atomic_t extracting; int cpci_debug; static struct cpci_hp_controller *controller; -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */ -static int thread_finished = 1; +static struct task_struct *cpci_thread; +static int thread_finished; static int enable_slot(struct hotplug_slot *slot); static int disable_slot(struct hotplug_slot *slot); static int set_attention_status(struct hotplug_slot *slot, u8 value); -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_adapter_status(struct hotplug_slot *slot, u8 * value); -static int get_latch_status(struct hotplug_slot *slot, u8 * value); +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_adapter_status(struct hotplug_slot *slot, u8 *value); +static int get_latch_status(struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, @@ -109,7 +106,7 @@ enable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); if (controller->ops->set_power) retval = controller->ops->set_power(slot, 1); @@ -122,25 +119,23 @@ disable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); down_write(&list_rwsem); /* Unconfigure device */ - dbg("%s - unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); + dbg("%s - unconfiguring slot %s", __func__, slot_name(slot)); if ((retval = cpci_unconfigure_slot(slot))) { err("%s - could not unconfigure slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); goto disable_error; } - dbg("%s - finished unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); + dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot)); /* Clear EXT (by setting it) */ if (cpci_clear_ext(slot)) { err("%s - could not clear EXT for slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); retval = -ENODEV; goto disable_error; } @@ -173,7 +168,7 @@ cpci_get_power_status(struct slot *slot) } static int -get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -182,7 +177,7 @@ get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) } static int -get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -197,14 +192,14 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) } static int -get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { *value = hotplug_slot->info->adapter_status; return 0; } static int -get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { *value = hotplug_slot->info->latch_status; return 0; @@ -215,7 +210,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); if (slot->dev) pci_dev_put(slot->dev); @@ -223,12 +217,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) } #define SLOT_NAME_SIZE 6 -static void -make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, - SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); -} int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) @@ -236,8 +224,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - char *name; - int status = -ENOMEM; + char name[SLOT_NAME_SIZE]; + int status; int i; if (!(controller && bus)) @@ -248,52 +236,52 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) * with the pci_hotplug subsystem. */ for (i = first; i <= last; ++i) { - slot = kmalloc(sizeof (struct slot), GFP_KERNEL); - if (!slot) + slot = kzalloc(sizeof (struct slot), GFP_KERNEL); + if (!slot) { + status = -ENOMEM; goto error; - memset(slot, 0, sizeof (struct slot)); + } hotplug_slot = - kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) + kzalloc(sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) { + status = -ENOMEM; goto error_slot; - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + } slot->hotplug_slot = hotplug_slot; - info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) + info = kzalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + status = -ENOMEM; goto error_hpslot; - memset(info, 0, sizeof (struct hotplug_slot_info)); + } hotplug_slot->info = info; - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) - goto error_info; - hotplug_slot->name = name; - slot->bus = bus; slot->number = i; slot->devfn = PCI_DEVFN(i, 0); + snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i); + hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - make_slot_name(slot); hotplug_slot->ops = &cpci_hotplug_slot_ops; /* * Initialize the slot info structure with some known * good values. */ - dbg("initializing slot %s", slot->hotplug_slot->name); + dbg("initializing slot %s", name); info->power_status = cpci_get_power_status(slot); info->attention_status = cpci_get_attention_status(slot); - dbg("registering slot %s", slot->hotplug_slot->name); - status = pci_hp_register(slot->hotplug_slot); + dbg("registering slot %s", name); + status = pci_hp_register(slot->hotplug_slot, bus, i, name); if (status) { err("pci_hp_register failed with error %d", status); - goto error_name; + goto error_info; } + dbg("slot registered with name: %s", slot_name(slot)); /* Add slot to our internal list */ down_write(&list_rwsem); @@ -302,8 +290,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) up_write(&list_rwsem); } return 0; -error_name: - kfree(name); error_info: kfree(info); error_hpslot: @@ -313,6 +299,7 @@ error_slot: error: return status; } +EXPORT_SYMBOL_GPL(cpci_hp_register_bus); int cpci_hp_unregister_bus(struct pci_bus *bus) @@ -331,7 +318,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) list_del(&slot->slot_list); slots--; - dbg("deregistering slot %s", slot->hotplug_slot->name); + dbg("deregistering slot %s", slot_name(slot)); status = pci_hp_deregister(slot->hotplug_slot); if (status) { err("pci_hp_deregister failed with error %d", @@ -343,15 +330,16 @@ cpci_hp_unregister_bus(struct pci_bus *bus) up_write(&list_rwsem); return status; } +EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); /* This is the interrupt mode interrupt handler */ static irqreturn_t -cpci_hp_intr(int irq, void *data, struct pt_regs *regs) +cpci_hp_intr(int irq, void *data) { dbg("entered cpci_hp_intr"); /* Check to see if it was our interrupt */ - if ((controller->irq_flags & SA_SHIRQ) && + if ((controller->irq_flags & IRQF_SHARED) && !controller->ops->check_irq(controller->dev_id)) { dbg("exited cpci_hp_intr, not our interrupt"); return IRQ_NONE; @@ -361,9 +349,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) controller->ops->disable_irq(); /* Trigger processing by the event thread */ - dbg("Signal event_semaphore"); - up(&event_semaphore); - dbg("exited cpci_hp_intr"); + wake_up_process(cpci_thread); return IRQ_HANDLED; } @@ -376,20 +362,19 @@ static int init_slots(int clear_ins) { struct slot *slot; - struct pci_dev* dev; + struct pci_dev *dev; - dbg("%s - enter", __FUNCTION__); + dbg("%s - enter", __func__); down_read(&list_rwsem); if (!slots) { up_read(&list_rwsem); return -1; } list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (clear_ins && cpci_check_and_clear_ins(slot)) dbg("%s - cleared INS for slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); if (dev) { if (update_adapter_status(slot->hotplug_slot, 1)) @@ -400,7 +385,7 @@ init_slots(int clear_ins) } } up_read(&list_rwsem); - dbg("%s - exit", __FUNCTION__); + dbg("%s - exit", __func__); return 0; } @@ -420,8 +405,7 @@ check_slots(void) } extracted = inserted = 0; list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (cpci_check_and_clear_ins(slot)) { /* * Some broken hardware (e.g. PLX 9054AB) asserts @@ -429,35 +413,34 @@ check_slots(void) */ if (slot->dev) { warn("slot %s already inserted", - slot->hotplug_slot->name); + slot_name(slot)); inserted++; continue; } /* Process insertion */ - dbg("%s - slot %s inserted", - __FUNCTION__, slot->hotplug_slot->name); + dbg("%s - slot %s inserted", __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (1) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); /* Configure device */ dbg("%s - configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); if (cpci_configure_slot(slot)) { err("%s - could not configure slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); continue; } dbg("%s - finished configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (2) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (update_latch_status(slot->hotplug_slot, 1)) warn("failure to update latch file"); @@ -470,18 +453,18 @@ check_slots(void) /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (3) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); inserted++; } else if (cpci_check_ext(slot)) { /* Process extraction request */ dbg("%s - slot %s extracted", - __FUNCTION__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (!slot->extracting) { if (update_latch_status(slot->hotplug_slot, 0)) { @@ -499,7 +482,7 @@ check_slots(void) * bother trying to tell the driver or not? */ err("card in slot %s was improperly removed", - slot->hotplug_slot->name); + slot_name(slot)); if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); slot->extracting = 0; @@ -525,17 +508,12 @@ event_thread(void *data) { int rc; - lock_kernel(); - daemonize("cpci_hp_eventd"); - unlock_kernel(); - - dbg("%s - event thread started", __FUNCTION__); + dbg("%s - event thread started", __func__); while (1) { dbg("event thread sleeping"); - down_interruptible(&event_semaphore); - dbg("event thread woken, thread_finished = %d", - thread_finished); - if (thread_finished || signal_pending(current)) + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (kthread_should_stop()) break; do { rc = check_slots(); @@ -543,20 +521,19 @@ event_thread(void *data) /* Give userspace a chance to handle extraction */ msleep(500); } else if (rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); + dbg("%s - error checking slots", __func__); thread_finished = 1; - break; + goto out; } - } while (atomic_read(&extracting) && !thread_finished); - if (thread_finished) + } while (atomic_read(&extracting) && !kthread_should_stop()); + if (kthread_should_stop()) break; /* Re-enable ENUM# interrupt */ - dbg("%s - re-enabling irq", __FUNCTION__); + dbg("%s - re-enabling irq", __func__); controller->ops->enable_irq(); } - dbg("%s - event thread signals exit", __FUNCTION__); - up(&thread_exit); + out: return 0; } @@ -566,12 +543,8 @@ poll_thread(void *data) { int rc; - lock_kernel(); - daemonize("cpci_hp_polld"); - unlock_kernel(); - while (1) { - if (thread_finished || signal_pending(current)) + if (kthread_should_stop() || signal_pending(current)) break; if (controller->ops->query_enum()) { do { @@ -580,50 +553,38 @@ poll_thread(void *data) /* Give userspace a chance to handle extraction */ msleep(500); } else if (rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); + dbg("%s - error checking slots", __func__); thread_finished = 1; - break; + goto out; } - } while (atomic_read(&extracting) && !thread_finished); + } while (atomic_read(&extracting) && !kthread_should_stop()); } msleep(100); } - dbg("poll thread signals exit"); - up(&thread_exit); + out: return 0; } static int cpci_start_thread(void) { - int pid; - - /* initialize our semaphores */ - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&thread_exit); - thread_finished = 0; - if (controller->irq) - pid = kernel_thread(event_thread, NULL, 0); + cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd"); else - pid = kernel_thread(poll_thread, NULL, 0); - if (pid < 0) { + cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld"); + if (IS_ERR(cpci_thread)) { err("Can't start up our thread"); - return -1; + return PTR_ERR(cpci_thread); } - dbg("Our thread pid = %d", pid); + thread_finished = 0; return 0; } static void cpci_stop_thread(void) { + kthread_stop(cpci_thread); thread_finished = 1; - dbg("thread finish command given"); - if (controller->irq) - up(&event_semaphore); - dbg("wait for thread to exit"); - down(&thread_exit); } int @@ -649,12 +610,13 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller) status = -ENODEV; } dbg("%s - acquired controller irq %d", - __FUNCTION__, new_controller->irq); + __func__, new_controller->irq); } if (!status) controller = new_controller; return status; } +EXPORT_SYMBOL_GPL(cpci_hp_register_controller); static void cleanup_slots(void) @@ -694,6 +656,7 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) status = -ENODEV; return status; } +EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); int cpci_hp_start(void) @@ -701,7 +664,7 @@ cpci_hp_start(void) static int first = 1; int status; - dbg("%s - enter", __FUNCTION__); + dbg("%s - enter", __func__); if (!controller) return -ENODEV; @@ -721,16 +684,17 @@ cpci_hp_start(void) status = cpci_start_thread(); if (status) return status; - dbg("%s - thread started", __FUNCTION__); + dbg("%s - thread started", __func__); if (controller->irq) { /* Start enum interrupt processing */ - dbg("%s - enabling irq", __FUNCTION__); + dbg("%s - enabling irq", __func__); controller->ops->enable_irq(); } - dbg("%s - exit", __FUNCTION__); + dbg("%s - exit", __func__); return 0; } +EXPORT_SYMBOL_GPL(cpci_hp_start); int cpci_hp_stop(void) @@ -739,12 +703,13 @@ cpci_hp_stop(void) return -ENODEV; if (controller->irq) { /* Stop enum interrupt processing */ - dbg("%s - disabling irq", __FUNCTION__); + dbg("%s - disabling irq", __func__); controller->ops->disable_irq(); } cpci_stop_thread(); return 0; } +EXPORT_SYMBOL_GPL(cpci_hp_stop); int __init cpci_hotplug_init(int debug) @@ -762,10 +727,3 @@ cpci_hotplug_exit(void) cpci_hp_stop(); cpci_hp_unregister_controller(controller); } - -EXPORT_SYMBOL_GPL(cpci_hp_register_controller); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); -EXPORT_SYMBOL_GPL(cpci_hp_register_bus); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); -EXPORT_SYMBOL_GPL(cpci_hp_start); -EXPORT_SYMBOL_GPL(cpci_hp_stop); diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 225b5e551dd..7d48ecae669 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -23,13 +23,12 @@ * Send feedback to <scottm@somanetworks.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/proc_fs.h> #include "../pci.h" -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define MY_NAME "cpci_hotplug" @@ -40,16 +39,14 @@ extern int cpci_debug; do { \ if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ + MY_NAME , ## arg); \ } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) - -u8 cpci_get_attention_status(struct slot* slot) +u8 cpci_get_attention_status(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -69,7 +66,7 @@ u8 cpci_get_attention_status(struct slot* slot) return hs_csr & 0x0008 ? 1 : 0; } -int cpci_set_attention_status(struct slot* slot, int status) +int cpci_set_attention_status(struct slot *slot, int status) { int hs_cap; u16 hs_csr; @@ -96,7 +93,7 @@ int cpci_set_attention_status(struct slot* slot, int status) return 1; } -u16 cpci_get_hs_csr(struct slot* slot) +u16 cpci_get_hs_csr(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -114,7 +111,7 @@ u16 cpci_get_hs_csr(struct slot* slot) return hs_csr; } -int cpci_check_and_clear_ins(struct slot* slot) +int cpci_check_and_clear_ins(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -143,7 +140,7 @@ int cpci_check_and_clear_ins(struct slot* slot) return ins; } -int cpci_check_ext(struct slot* slot) +int cpci_check_ext(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -164,7 +161,7 @@ int cpci_check_ext(struct slot* slot) return ext; } -int cpci_clear_ext(struct slot* slot) +int cpci_clear_ext(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -190,7 +187,7 @@ int cpci_clear_ext(struct slot* slot) return 0; } -int cpci_led_on(struct slot* slot) +int cpci_led_on(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -212,14 +209,14 @@ int cpci_led_on(struct slot* slot) hs_cap + 2, hs_csr)) { err("Could not set LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } return 0; } -int cpci_led_off(struct slot* slot) +int cpci_led_off(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -241,7 +238,7 @@ int cpci_led_off(struct slot* slot) hs_cap + 2, hs_csr)) { err("Could not clear LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } @@ -253,12 +250,15 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -int cpci_configure_slot(struct slot* slot) +int cpci_configure_slot(struct slot *slot) { - unsigned char busnr; - struct pci_bus *child; + struct pci_dev *dev; + struct pci_bus *parent; + int ret = 0; + + dbg("%s - enter", __func__); - dbg("%s - enter", __FUNCTION__); + pci_lock_rescan_remove(); if (slot->dev == NULL) { dbg("pci_dev null, finding %02x:%02x:%x", @@ -276,51 +276,57 @@ int cpci_configure_slot(struct slot* slot) * we will only call this case when lookup fails. */ n = pci_scan_slot(slot->bus, slot->devfn); - dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); - if (n > 0) - pci_bus_add_devices(slot->bus); + dbg("%s: pci_scan_slot returned %d", __func__, n); slot->dev = pci_get_slot(slot->bus, slot->devfn); if (slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); - return 1; + ret = -ENODEV; + goto out; } } + parent = slot->dev->bus; - if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr); - child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr); - pci_do_scan_bus(child); - pci_bus_size_bridges(child); - } + list_for_each_entry(dev, &parent->devices, bus_list) + if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) + continue; + if (pci_is_bridge(dev)) + pci_hp_add_bridge(dev); - pci_bus_assign_resources(slot->dev->bus); - dbg("%s - exit", __FUNCTION__); - return 0; + pci_assign_unassigned_bridge_resources(parent->self); + + pci_bus_add_devices(parent); + + out: + pci_unlock_rescan_remove(); + dbg("%s - exit", __func__); + return ret; } -int cpci_unconfigure_slot(struct slot* slot) +int cpci_unconfigure_slot(struct slot *slot) { - int i; - struct pci_dev *dev; + struct pci_dev *dev, *temp; - dbg("%s - enter", __FUNCTION__); + dbg("%s - enter", __func__); if (!slot->dev) { err("No device for slot %02x\n", slot->number); return -ENODEV; } - for (i = 0; i < 8; i++) { - dev = pci_get_slot(slot->bus, - PCI_DEVFN(PCI_SLOT(slot->devfn), i)); - if (dev) { - pci_remove_bus_device(dev); - pci_dev_put(dev); - } + pci_lock_rescan_remove(); + + list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) + continue; + pci_dev_get(dev); + pci_stop_and_remove_bus_device(dev); + pci_dev_put(dev); } pci_dev_put(slot->dev); slot->dev = NULL; - dbg("%s - exit", __FUNCTION__); + pci_unlock_rescan_remove(); + + dbg("%s - exit", __func__); return 0; } diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index 2d4639d6841..04fcd781140 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -13,14 +13,14 @@ * option) any later version. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along @@ -34,7 +34,6 @@ * Send feedback to <scottm@somanetworks.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> @@ -54,16 +53,16 @@ #define dbg(format, arg...) \ do { \ - if(debug) \ + if (debug) \ printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ + MY_NAME , ## arg); \ } while(0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; +static bool debug; static char *bridge; static u8 bridge_busnr; static u8 bridge_slot; @@ -79,13 +78,13 @@ static struct cpci_hp_controller generic_hpc; static int __init validate_parameters(void) { - char* str; - char* p; + char *str; + char *p; unsigned long tmp; if(!bridge) { info("not configured, disabling."); - return 1; + return -EINVAL; } str = bridge; if(!*str) @@ -143,24 +142,27 @@ static int query_enum(void) static int __init cpcihp_generic_init(void) { int status; - struct resource* r; - struct pci_dev* dev; + struct resource *r; + struct pci_dev *dev; info(DRIVER_DESC " version: " DRIVER_VERSION); status = validate_parameters(); - if(status != 0) + if (status) return status; r = request_region(port, 1, "#ENUM hotswap signal register"); if(!r) return -EBUSY; - dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0)); + dev = pci_get_domain_bus_and_slot(0, bridge_busnr, + PCI_DEVFN(bridge_slot, 0)); if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { err("Invalid bridge device %s", bridge); + pci_dev_put(dev); return -EINVAL; } bus = dev->subordinate; + pci_dev_put(dev); memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); generic_hpc_ops.query_enum = query_enum; diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index f7cb00da38d..6757b3ef7e1 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -13,14 +13,14 @@ * option) any later version. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along @@ -30,13 +30,13 @@ * Send feedback to <scottm@somanetworks.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/pci.h> -#include <linux/signal.h> /* SA_SHIRQ */ +#include <linux/interrupt.h> +#include <linux/signal.h> /* IRQF_SHARED */ #include "cpci_hotplug.h" #include "cpcihp_zt5550.h" @@ -48,17 +48,17 @@ #define dbg(format, arg...) \ do { \ - if(debug) \ + if (debug) \ printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ + MY_NAME , ## arg); \ } while(0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; -static int poll; +static bool debug; +static bool poll; static struct cpci_hp_controller_ops zt5550_hpc_ops; static struct cpci_hp_controller zt5550_hpc; @@ -95,8 +95,8 @@ static int zt5550_hc_config(struct pci_dev *pdev) hc_dev = pdev; dbg("hc_dev = %p", hc_dev); - dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); - dbg("pci resource len %lx", pci_resource_len(hc_dev, 1)); + dbg("pci resource start %llx", (unsigned long long)pci_resource_start(hc_dev, 1)); + dbg("pci resource len %llx", (unsigned long long)pci_resource_len(hc_dev, 1)); if(!request_mem_region(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1), MY_NAME)) { @@ -108,8 +108,9 @@ static int zt5550_hc_config(struct pci_dev *pdev) hc_registers = ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); if(!hc_registers) { - err("cannot remap MMIO region %lx @ %lx", - pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); + err("cannot remap MMIO region %llx @ %llx", + (unsigned long long)pci_resource_len(hc_dev, 1), + (unsigned long long)pci_resource_start(hc_dev, 1)); ret = -ENODEV; goto exit_release_region; } @@ -219,7 +220,7 @@ static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id zt5550_hpc.ops = &zt5550_hpc_ops; if(!poll) { zt5550_hpc.irq = hc_dev->irq; - zt5550_hpc.irq_flags = SA_SHIRQ; + zt5550_hpc.irq_flags = IRQF_SHARED; zt5550_hpc.dev_id = hc_dev; zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; @@ -270,7 +271,7 @@ init_hc_error: } -static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) +static void zt5550_hc_remove_one(struct pci_dev *pdev) { cpci_hp_stop(); cpci_hp_unregister_bus(bus0); @@ -284,24 +285,28 @@ static struct pci_device_id zt5550_hc_pci_tbl[] = { { 0, } }; MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); - + static struct pci_driver zt5550_hc_driver = { .name = "zt5550_hc", .id_table = zt5550_hc_pci_tbl, .probe = zt5550_hc_init_one, - .remove = __devexit_p(zt5550_hc_remove_one), + .remove = zt5550_hc_remove_one, }; static int __init zt5550_init(void) { - struct resource* r; + struct resource *r; + int rc; info(DRIVER_DESC " version: " DRIVER_VERSION); r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); if(!r) return -EBUSY; - return pci_register_driver(&zt5550_hc_driver); + rc = pci_register_driver(&zt5550_hc_driver); + if(rc < 0) + release_region(ENUM_PORT, 1); + return rc; } static void __exit diff --git a/drivers/pci/hotplug/cpcihp_zt5550.h b/drivers/pci/hotplug/cpcihp_zt5550.h index bebc6060a55..9a57fda5348 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.h +++ b/drivers/pci/hotplug/cpcihp_zt5550.h @@ -13,14 +13,14 @@ * option) any later version. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along @@ -55,7 +55,7 @@ #define HC_CMD_REG 0x0C #define ARB_CONFIG_GNT_REG 0x10 #define ARB_CONFIG_CFG_REG 0x12 -#define ARB_CONFIG_REG 0x10 +#define ARB_CONFIG_REG 0x10 #define ISOL_CONFIG_REG 0x18 #define FAULT_STATUS_REG 0x20 #define FAULT_CONFIG_REG 0x24 diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index 092491e25ef..0450f405807 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -28,10 +28,11 @@ #ifndef _CPQPHP_H #define _CPQPHP_H -#include "pci_hotplug.h" #include <linux/interrupt.h> #include <asm/io.h> /* for read? and write? functions */ #include <linux/delay.h> /* for delays */ +#include <linux/mutex.h> +#include <linux/sched.h> /* for signal_pending() */ #define MY_NAME "cpqphp" @@ -150,25 +151,25 @@ struct ctrl_reg { /* offset */ /* offsets to the controller registers based on the above structure layout */ enum ctrl_offsets { - SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), MISC = offsetof(struct ctrl_reg, misc), LED_CONTROL = offsetof(struct ctrl_reg, led_control), INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), - INT_MASK = offsetof(struct ctrl_reg, int_mask), - CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), - GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), - NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), - SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), - CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), @@ -190,7 +191,9 @@ struct hrt { u32 reserved2; } __attribute__ ((packed)); -/* offsets to the hotplug resource table registers based on the above structure layout */ +/* offsets to the hotplug resource table registers based on the above + * structure layout + */ enum hrt_offsets { SIG0 = offsetof(struct hrt, sig0), SIG1 = offsetof(struct hrt, sig1), @@ -217,18 +220,20 @@ struct slot_rt { u16 pre_mem_length; } __attribute__ ((packed)); -/* offsets to the hotplug slot resource table registers based on the above structure layout */ +/* offsets to the hotplug slot resource table registers based on the above + * structure layout + */ enum slot_rt_offsets { DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), }; struct pci_func { @@ -250,7 +255,7 @@ struct pci_func { struct pci_resource *io_head; struct pci_resource *bus_head; struct timer_list *p_task_event; - struct pci_dev* pci_dev; + struct pci_dev *pci_dev; }; struct slot { @@ -273,7 +278,7 @@ struct slot { }; struct pci_resource { - struct pci_resource * next; + struct pci_resource *next; u32 base; u32 length; }; @@ -286,8 +291,8 @@ struct event_info { struct controller { struct controller *next; u32 ctrl_int_comp; - struct semaphore crit_sect; /* critical section semaphore */ - void __iomem *hpc_reg; /* cookie for our pci controller location */ + struct mutex crit_sect; /* critical section mutex */ + void __iomem *hpc_reg; /* cookie for our pci controller location */ struct pci_resource *mem_head; struct pci_resource *p_mem_head; struct pci_resource *io_head; @@ -299,14 +304,12 @@ struct controller { u8 next_event; u8 interrupt; u8 cfgspc_irq; - u8 bus; /* bus number for the pci hotplug controller */ + u8 bus; /* bus number for the pci hotplug controller */ u8 rev; u8 slot_device_offset; u8 first_slot; u8 add_support; u8 push_flag; - enum pci_bus_speed speed; - enum pci_bus_speed speed_capability; u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ @@ -317,6 +320,7 @@ struct controller { u16 vendor_id; struct work_struct int_task_event; wait_queue_head_t queue; /* sleep & wake process */ + struct dentry *dentry; /* debugfs dentry */ }; struct irq_mapping { @@ -399,44 +403,52 @@ struct resource_lists { #define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" -/* sysfs functions for the hotplug controller info */ -extern void cpqhp_create_ctrl_files (struct controller *ctrl); +/* debugfs functions for the hotplug controller info */ +void cpqhp_initialize_debugfs(void); +void cpqhp_shutdown_debugfs(void); +void cpqhp_create_debugfs_files(struct controller *ctrl); +void cpqhp_remove_debugfs_files(struct controller *ctrl); /* controller functions */ -extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); -extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start); -extern int cpqhp_event_start_thread (void); -extern void cpqhp_event_stop_thread (void); -extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); -extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); +void cpqhp_pushbutton_thread(unsigned long event_pointer); +irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data); +int cpqhp_find_available_resources(struct controller *ctrl, + void __iomem *rom_start); +int cpqhp_event_start_thread(void); +void cpqhp_event_stop_thread(void); +struct pci_func *cpqhp_slot_create(unsigned char busnumber); +struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device, + unsigned char index); +int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func); +int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func); +int cpqhp_hardware_test(struct controller *ctrl, int test_num); /* resource functions */ -extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); +int cpqhp_resource_sort_and_combine (struct pci_resource **head); /* pci functions */ -extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); -extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); -extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); -extern void cpqhp_destroy_board_resources (struct pci_func * func); -extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void cpqhp_destroy_resource_list (struct resource_lists * resources); -extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int cpqhp_unconfigure_device (struct pci_func* func); +int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, + u8 slot); +int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug); +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func); +int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func); +int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func); +int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot); +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func); +void cpqhp_destroy_board_resources(struct pci_func *func); +int cpqhp_return_board_resources(struct pci_func *func, + struct resource_lists *resources); +void cpqhp_destroy_resource_list(struct resource_lists *resources); +int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func); +int cpqhp_unconfigure_device(struct pci_func *func); /* Global variables */ extern int cpqhp_debug; extern int cpqhp_legacy_mode; extern struct controller *cpqhp_ctrl_list; extern struct pci_func *cpqhp_slot_list[256]; +extern struct irq_routing_table *cpqhp_routing_table; /* these can be gotten rid of, but for debugging they are purty */ extern u8 cpqhp_nic_irq; @@ -445,13 +457,18 @@ extern u8 cpqhp_disk_irq; /* inline functions */ +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + /* * return_resource * * Puts node back in the resource list pointed to by head - * */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) +static inline void return_resource(struct pci_resource **head, + struct pci_resource *node) { if (!node || !head) return; @@ -462,7 +479,7 @@ static inline void return_resource(struct pci_resource **head, struct pci_resour static inline void set_SOGO(struct controller *ctrl) { u16 misc; - + misc = readw(ctrl->hpc_reg + MISC); misc = (misc | 0x0001) & 0xFFFB; writew(misc, ctrl->hpc_reg + MISC); @@ -472,7 +489,7 @@ static inline void set_SOGO(struct controller *ctrl) static inline void amber_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= (0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -482,7 +499,7 @@ static inline void amber_LED_on(struct controller *ctrl, u8 slot) static inline void amber_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -495,7 +512,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= (0x01010000L << slot); - + return led_control ? 1 : 0; } @@ -503,7 +520,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) static inline void green_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= 0x0101L << slot; writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -512,7 +529,7 @@ static inline void green_LED_on(struct controller *ctrl, u8 slot) static inline void green_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -522,7 +539,7 @@ static inline void green_LED_off(struct controller *ctrl, u8 slot) static inline void green_LED_blink(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); led_control |= (0x0001L << slot); @@ -566,22 +583,21 @@ static inline u8 read_slot_enable(struct controller *ctrl) } -/* +/** * get_controller_speed - find the current frequency/mode of controller. * * @ctrl: controller to get frequency/mode for. * * Returns controller speed. - * */ static inline u8 get_controller_speed(struct controller *ctrl) { u8 curr_freq; - u16 misc; - + u16 misc; + if (ctrl->pcix_support) { curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); - if ((curr_freq & 0xB0) == 0xB0) + if ((curr_freq & 0xB0) == 0xB0) return PCI_SPEED_133MHz_PCIX; if ((curr_freq & 0xA0) == 0xA0) return PCI_SPEED_100MHz_PCIX; @@ -593,19 +609,18 @@ static inline u8 get_controller_speed(struct controller *ctrl) return PCI_SPEED_33MHz; } - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } - -/* + +/** * get_adapter_speed - find the max supported frequency/mode of adapter. * * @ctrl: hotplug controller. * @hp_slot: hotplug slot where adapter is installed. * * Returns adapter speed. - * */ static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot) { @@ -663,14 +678,15 @@ static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot) } -static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot) +static inline int cpq_get_latch_status(struct controller *ctrl, + struct slot *slot) { u32 status; u8 hp_slot; hp_slot = slot->device - ctrl->slot_device_offset; dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", - __FUNCTION__, slot->device, ctrl->slot_device_offset); + __func__, slot->device, ctrl->slot_device_offset); status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); @@ -678,7 +694,8 @@ static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slo } -static inline int get_presence_status(struct controller *ctrl, struct slot *slot) +static inline int get_presence_status(struct controller *ctrl, + struct slot *slot) { int presence_save = 0; u8 hp_slot; @@ -687,25 +704,18 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot hp_slot = slot->device - ctrl->slot_device_offset; tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) + >> hp_slot) & 0x02; return presence_save; } -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%d", slot->number); -} - - static inline int wait_for_ctrl_irq(struct controller *ctrl) { DECLARE_WAITQUEUE(wait, current); int retval = 0; - dbg("%s - start\n", __FUNCTION__); + dbg("%s - start\n", __func__); add_wait_queue(&ctrl->queue, &wait); /* Sleep for up to 1 second to wait for the LED to change. */ msleep_interruptible(1000); @@ -713,9 +723,16 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl) if (signal_pending(current)) retval = -EINTR; - dbg("%s - end\n", __FUNCTION__); + dbg("%s - end\n", __func__); return retval; } -#endif +#include <asm/pci_x86.h> +static inline int cpqhp_routing_table_length(void) +{ + BUG_ON(cpqhp_routing_table == NULL); + return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) / + sizeof(struct irq_info)); +} +#endif diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 9aed8efe6a1..4aaee746df8 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -25,11 +25,9 @@ * Send feedback to <greg@kroah.com> * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, - * Torben Mathiasen <torben.mathiasen@hp.com> - * + * Torben Mathiasen <torben.mathiasen@hp.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -38,6 +36,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -45,7 +44,6 @@ #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ /* Global variables */ @@ -53,13 +51,14 @@ int cpqhp_debug; int cpqhp_legacy_mode; struct controller *cpqhp_ctrl_list; /* = NULL */ struct pci_func *cpqhp_slot_list[256]; +struct irq_routing_table *cpqhp_routing_table; /* local variables */ static void __iomem *smbios_table; static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; -static int power_mode; -static int debug; +static bool power_mode; +static bool debug; static int initialized; #define DRIVER_VERSION "0.9.8" @@ -78,33 +77,6 @@ MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 -static int one_time_init (void); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int process_SI (struct hotplug_slot *slot); -static int process_SS (struct hotplug_slot *slot); -static int hardware_test (struct hotplug_slot *slot, u32 value); -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_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); - -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = process_SI, - .disable_slot = process_SS, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - static inline int is_slot64bit(struct slot *slot) { return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0; @@ -117,14 +89,12 @@ static inline int is_slot66mhz(struct slot *slot) /** * detect_SMBIOS_pointer - find the System Management BIOS Table in mem region. - * * @begin: begin pointer for region to be scanned. * @end: end pointer for region to be scanned. * - * Returns pointer to the head of the SMBIOS tables (or NULL) - * + * Returns pointer to the head of the SMBIOS tables (or %NULL). */ -static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end) +static void __iomem *detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end) { void __iomem *fp; void __iomem *endp; @@ -146,7 +116,7 @@ static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *e break; } } - + if (!status) fp = NULL; @@ -157,11 +127,11 @@ static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *e /** * init_SERR - Initializes the per slot SERR generation. + * @ctrl: controller to use * * For unexpected switch opens - * */ -static int init_SERR(struct controller * ctrl) +static int init_SERR(struct controller *ctrl) { u32 tempdword; u32 number_of_slots; @@ -173,7 +143,7 @@ static int init_SERR(struct controller * ctrl) tempdword = ctrl->first_slot; number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // Loop through slots + /* Loop through slots */ while (number_of_slots) { physical_slot = tempdword; writeb(0, ctrl->hpc_reg + SLOT_SERR); @@ -184,54 +154,56 @@ static int init_SERR(struct controller * ctrl) return 0; } - -/* nice debugging output */ -static int pci_print_IRQ_route (void) +static int init_cpqhp_routing_table(void) { - struct irq_routing_table *routing_table; int len; - int loop; - - u8 tbus, tdevice, tslot; - routing_table = pcibios_get_irq_routing_table(); - if (routing_table == NULL) { - err("No BIOS Routing Table??? Not good\n"); + cpqhp_routing_table = pcibios_get_irq_routing_table(); + if (cpqhp_routing_table == NULL) return -ENOMEM; - } - len = (routing_table->size - sizeof(struct irq_routing_table)) / - sizeof(struct irq_info); - // Make sure I got at least one entry + len = cpqhp_routing_table_length(); if (len == 0) { - kfree(routing_table); + kfree(cpqhp_routing_table); + cpqhp_routing_table = NULL; return -1; } - dbg("bus dev func slot\n"); + return 0; +} + +/* nice debugging output */ +static void pci_print_IRQ_route(void) +{ + int len; + int loop; + u8 tbus, tdevice, tslot; + + len = cpqhp_routing_table_length(); + dbg("bus dev func slot\n"); for (loop = 0; loop < len; ++loop) { - tbus = routing_table->slots[loop].bus; - tdevice = routing_table->slots[loop].devfn; - tslot = routing_table->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); } - kfree(routing_table); - return 0; + return; } /** * get_subsequent_smbios_entry: get the next entry from bios table. - * - * Gets the first entry if previous == NULL - * Otherwise, returns the next entry - * Uses global SMBIOS Table pointer - * + * @smbios_start: where to start in the SMBIOS table + * @smbios_table: location of the SMBIOS table * @curr: %NULL or pointer to previously returned structure * - * returns a pointer to an SMBIOS structure or NULL if none found + * Gets the first entry if previous == NULL; + * otherwise, returns the next entry. + * Uses global SMBIOS Table pointer. + * + * Returns a pointer to an SMBIOS structure or NULL if none found. */ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *smbios_table, @@ -243,9 +215,9 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *p_max; if (!smbios_table || !curr) - return(NULL); + return NULL; - // set p_max to the end of the table + /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); p_temp = curr; @@ -254,35 +226,35 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, while ((p_temp < p_max) && !bail) { /* Look for the double NULL terminator * The first condition is the previous byte - * and the second is the curr */ - if (!previous_byte && !(readb(p_temp))) { + * and the second is the curr + */ + if (!previous_byte && !(readb(p_temp))) bail = 1; - } previous_byte = readb(p_temp); p_temp++; } - if (p_temp < p_max) { + if (p_temp < p_max) return p_temp; - } else { + else return NULL; - } } /** - * get_SMBIOS_entry - * - * @type:SMBIOS structure type to be returned + * get_SMBIOS_entry - return the requested SMBIOS entry or %NULL + * @smbios_start: where to start in the SMBIOS table + * @smbios_table: location of the SMBIOS table + * @type: SMBIOS structure type to be returned * @previous: %NULL or pointer to previously returned structure * - * Gets the first entry of the specified type if previous == NULL + * Gets the first entry of the specified type if previous == %NULL; * Otherwise, returns the next entry of the given type. - * Uses global SMBIOS Table pointer - * Uses get_subsequent_smbios_entry + * Uses global SMBIOS Table pointer. + * Uses get_subsequent_smbios_entry. * - * returns a pointer to an SMBIOS structure or %NULL if none found + * Returns a pointer to an SMBIOS structure or %NULL if none found. */ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, void __iomem *smbios_table, @@ -292,21 +264,18 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, if (!smbios_table) return NULL; - if (!previous) { + if (!previous) previous = smbios_start; - } else { + else previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } - while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + while (previous) + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } else { + else break; - } - } return previous; } @@ -315,144 +284,14 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } -static int ctrl_slot_setup(struct controller *ctrl, - void __iomem *smbios_start, - void __iomem *smbios_table) -{ - struct slot *new_slot; - u8 number_of_slots; - u8 slot_device; - u8 slot_number; - u8 ctrl_slot; - u32 tempdword; - void __iomem *slot_entry= NULL; - int result = -ENOMEM; - - dbg("%s\n", __FUNCTION__); - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - if (!new_slot) - goto error; - - memset(new_slot, 0, sizeof(struct slot)); - new_slot->hotplug_slot = kmalloc(sizeof(*(new_slot->hotplug_slot)), - GFP_KERNEL); - if (!new_slot->hotplug_slot) - goto error_slot; - memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - - new_slot->hotplug_slot->info = - kmalloc(sizeof(*(new_slot->hotplug_slot->info)), - GFP_KERNEL); - if (!new_slot->hotplug_slot->info) - goto error_hpslot; - memset(new_slot->hotplug_slot->info, 0, - sizeof(struct hotplug_slot_info)); - new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!new_slot->hotplug_slot->name) - goto error_info; - - new_slot->ctrl = ctrl; - new_slot->bus = ctrl->bus; - new_slot->device = slot_device; - new_slot->number = slot_number; - dbg("slot->number = %d\n",new_slot->number); - - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, - slot_entry); - - while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { - slot_entry = get_SMBIOS_entry(smbios_start, - smbios_table, 9, slot_entry); - } - - new_slot->p_sm_slot = slot_entry; - - init_timer(&new_slot->task_event); - new_slot->task_event.expires = jiffies + 5 * HZ; - new_slot->task_event.function = cpqhp_pushbutton_thread; - - //FIXME: these capabilities aren't used but if they are - // they need to be correctly implemented - new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; - new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; - - if (is_slot64bit(new_slot)) - new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; - if (is_slot66mhz(new_slot)) - new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == PCI_SPEED_66MHz) - new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; - - ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - - // Check presence - new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - // Check the switch state - new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - // Check the slot enable - new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; - - /* register this slot with the hotplug pci core */ - new_slot->hotplug_slot->release = &release_slot; - new_slot->hotplug_slot->private = new_slot; - make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); - new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - - new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); - new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); - new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); - new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); - - dbg ("registering bus %d, dev %d, number %d, " - "ctrl->slot_device_offset %d, slot %d\n", - new_slot->bus, new_slot->device, - new_slot->number, ctrl->slot_device_offset, - slot_number); - result = pci_hp_register (new_slot->hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - goto error_name; - } - - new_slot->next = ctrl->slot; - ctrl->slot = new_slot; - - number_of_slots--; - slot_device++; - slot_number++; - } - - return 0; - -error_name: - kfree(new_slot->hotplug_slot->name); -error_info: - kfree(new_slot->hotplug_slot->info); -error_hpslot: - kfree(new_slot->hotplug_slot); -error_slot: - kfree(new_slot); -error: - return result; -} - -static int ctrl_slot_cleanup (struct controller * ctrl) +static int ctrl_slot_cleanup (struct controller *ctrl) { struct slot *old_slot, *next_slot; @@ -466,111 +305,98 @@ static int ctrl_slot_cleanup (struct controller * ctrl) old_slot = next_slot; } - //Free IRQ associated with hot plug device + cpqhp_remove_debugfs_files(ctrl); + + /* Free IRQ associated with hot plug device */ free_irq(ctrl->interrupt, ctrl); - //Unmap the memory + /* Unmap the memory */ iounmap(ctrl->hpc_reg); - //Finally reclaim PCI mem + /* Finally reclaim PCI mem */ release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); - return(0); + return 0; } -//============================================================================ -// function: get_slot_mapping -// -// Description: Attempts to determine a logical slot mapping for a PCI -// device. Won't work for more than one PCI-PCI bridge -// in a slot. -// -// Input: u8 bus_num - bus number of PCI device -// u8 dev_num - device number of PCI device -// u8 *slot - Pointer to u8 where slot number will -// be returned -// -// Output: SUCCESS or FAILURE -//============================================================================= +/** + * get_slot_mapping - determine logical slot mapping for PCI device + * + * Won't work for more than one PCI-PCI bridge in a slot. + * + * @bus_num - bus number of PCI device + * @dev_num - device number of PCI device + * @slot - Pointer to u8 where slot number will be returned + * + * Output: SUCCESS or FAILURE + */ static int get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) { - struct irq_routing_table *PCIIRQRoutingInfoLength; u32 work; long len; long loop; u8 tbus, tdevice, tslot, bridgeSlot; - dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot); + dbg("%s: %p, %d, %d, %p\n", __func__, bus, bus_num, dev_num, slot); bridgeSlot = 0xFF; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - kfree(PCIIRQRoutingInfoLength); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn >> 3; + tslot = cpqhp_routing_table->slots[loop].slot; if ((tbus == bus_num) && (tdevice == dev_num)) { *slot = tslot; - kfree(PCIIRQRoutingInfoLength); return 0; } else { /* Did not get a match on the target PCI device. Check - * if the current IRQ table entry is a PCI-to-PCI bridge - * device. If so, and it's secondary bus matches the - * bus number for the target device, I need to save the - * bridge's slot number. If I can not find an entry for - * the target device, I will have to assume it's on the - * other side of the bridge, and assign it the bridge's - * slot. */ + * if the current IRQ table entry is a PCI-to-PCI + * bridge device. If so, and it's secondary bus + * matches the bus number for the target device, I need + * to save the bridge's slot number. If I can not find + * an entry for the target device, I will have to + * assume it's on the other side of the bridge, and + * assign it the bridge's slot. + */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), - PCI_REVISION_ID, &work); + PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); // See if bridge's secondary bus matches target bus. - if (((work >> 8) & 0x000000FF) == (long) bus_num) { + if (((work >> 8) & 0x000000FF) == (long) bus_num) bridgeSlot = tslot; - } } } } - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the - // slot number for the bridge. + /* If we got here, we didn't find an entry in the IRQ mapping table for + * the target PCI device. If we did determine that the target device + * is on the other side of a PCI-to-PCI bridge, return the slot number + * for the bridge. + */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; - kfree(PCIIRQRoutingInfoLength); return 0; } - kfree(PCIIRQRoutingInfoLength); - // Couldn't find an entry in the routing table for this PCI device + /* Couldn't find an entry in the routing table for this PCI device */ return -1; } /** * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off - * + * @ctrl: struct controller to use + * @func: PCI device/function info + * @status: LED control flag: 1 = LED on, 0 = LED off */ static int cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, @@ -579,38 +405,39 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, u8 hp_slot; if (func == NULL) - return(1); + return 1; hp_slot = func->device - ctrl->slot_device_offset; - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); + /* Wait for exclusive access to hardware */ + mutex_lock(&ctrl->crit_sect); - if (status == 1) { + if (status == 1) amber_LED_on (ctrl, hp_slot); - } else if (status == 0) { + else if (status == 0) amber_LED_off (ctrl, hp_slot); - } else { - // Done with exclusive hardware access - up(&ctrl->crit_sect); - return(1); + else { + /* Done with exclusive hardware access */ + mutex_unlock(&ctrl->crit_sect); + return 1; } set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - // Done with exclusive hardware access - up(&ctrl->crit_sect); + /* Done with exclusive hardware access */ + mutex_unlock(&ctrl->crit_sect); - return(0); + return 0; } /** * set_attention_status - Turns the Amber LED for a slot on or off - * + * @hotplug_slot: slot to change LED on + * @status: LED control flag */ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) { @@ -622,7 +449,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -649,7 +476,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -681,7 +508,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -694,7 +521,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot) if (!slot_func) return -ENODEV; - dbg("In %s, slot_func = %p, ctrl = %p\n", __FUNCTION__, slot_func, ctrl); + dbg("In %s, slot_func = %p, ctrl = %p\n", __func__, slot_func, ctrl); return cpqhp_process_SS(ctrl, slot_func); } @@ -704,9 +531,9 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); - return cpqhp_hardware_test(ctrl, value); + return cpqhp_hardware_test(ctrl, value); } @@ -715,7 +542,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_slot_enabled(ctrl, slot); return 0; @@ -725,8 +552,8 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_attention_status(ctrl, slot); return 0; @@ -737,7 +564,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_latch_status(ctrl, slot); @@ -749,35 +576,239 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_presence_status(ctrl, slot); return 0; } -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + .set_attention_status = set_attention_status, + .enable_slot = process_SI, + .disable_slot = process_SS, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, +}; + +#define SLOT_NAME_SIZE 10 + +static int ctrl_slot_setup(struct controller *ctrl, + void __iomem *smbios_start, + void __iomem *smbios_table) { - struct slot *slot = hotplug_slot->private; - struct controller *ctrl = slot->ctrl; + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *hotplug_slot_info; + struct pci_bus *bus = ctrl->pci_bus; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + char name[SLOT_NAME_SIZE]; + void __iomem *slot_entry= NULL; + int result; + + dbg("%s\n", __func__); - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - *value = ctrl->speed_capability; + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + result = -ENOMEM; + goto error; + } + + slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), + GFP_KERNEL); + if (!slot->hotplug_slot) { + result = -ENOMEM; + goto error_slot; + } + hotplug_slot = slot->hotplug_slot; + + hotplug_slot->info = kzalloc(sizeof(*(hotplug_slot->info)), + GFP_KERNEL); + if (!hotplug_slot->info) { + result = -ENOMEM; + goto error_hpslot; + } + hotplug_slot_info = hotplug_slot->info; + + slot->ctrl = ctrl; + slot->bus = ctrl->bus; + slot->device = slot_device; + slot->number = slot_number; + dbg("slot->number = %u\n", slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, + slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != + slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, + smbios_table, 9, slot_entry); + } + + slot->p_sm_slot = slot_entry; + + init_timer(&slot->task_event); + slot->task_event.expires = jiffies + 5 * HZ; + slot->task_event.function = cpqhp_pushbutton_thread; + + /*FIXME: these capabilities aren't used but if they are + * they need to be correctly implemented + */ + slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(slot)) + slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(slot)) + slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (bus->cur_bus_speed == PCI_SPEED_66MHz) + slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = + slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + /* Check presence */ + slot->capabilities |= + ((((~tempdword) >> 23) | + ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + /* Check the switch state */ + slot->capabilities |= + ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + /* Check the slot enable */ + slot->capabilities |= + ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + hotplug_slot->release = &release_slot; + hotplug_slot->private = slot; + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); + hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); + hotplug_slot_info->attention_status = + cpq_get_attention_status(ctrl, slot); + hotplug_slot_info->latch_status = + cpq_get_latch_status(ctrl, slot); + hotplug_slot_info->adapter_status = + get_presence_status(ctrl, slot); + + dbg("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", + slot->bus, slot->device, + slot->number, ctrl->slot_device_offset, + slot_number); + result = pci_hp_register(hotplug_slot, + ctrl->pci_dev->bus, + slot->device, + name); + if (result) { + err("pci_hp_register failed with error %d\n", result); + goto error_info; + } + + slot->next = ctrl->slot; + ctrl->slot = slot; + + number_of_slots--; + slot_device++; + slot_number++; + } return 0; +error_info: + kfree(hotplug_slot_info); +error_hpslot: + kfree(hotplug_slot); +error_slot: + kfree(slot); +error: + return result; } -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static int one_time_init(void) { - struct slot *slot = hotplug_slot->private; - struct controller *ctrl = slot->ctrl; + int loop; + int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + if (initialized) + return 0; - *value = ctrl->speed; + power_mode = 0; - return 0; + retval = init_cpqhp_routing_table(); + if (retval) + goto error; + + if (cpqhp_debug) + pci_print_IRQ_route(); + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) + cpqhp_slot_list[loop] = NULL; + + /* FIXME: We also need to hook the NMI handler eventually. + * this also needs to be worked with Christoph + * register_NMI_handler(); + */ + /* Map rom address */ + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific + * hardware + */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, + cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO; + goto error_rom_start; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), + readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO; + goto error_smbios_start; + } + + initialized = 1; + + return retval; + +error_smbios_start: + iounmap(smbios_start); +error_rom_start: + iounmap(cpqhp_rom_start); +error: + return retval; } static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -785,7 +816,6 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u8 num_of_slots = 0; u8 hp_slot = 0; u8 device; - u8 rev; u8 bus_cap; u16 temp_word; u16 vendor_id; @@ -794,6 +824,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u32 rc; struct controller *ctrl; struct pci_func *func; + struct pci_bus *bus; int err; err = pci_enable_device(pdev); @@ -803,241 +834,233 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } - // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + bus = pdev->subordinate; + if (!bus) { + dev_notice(&pdev->dev, "the device is not a bridge, skipping\n"); + rc = -ENODEV; + goto err_disable_device; + } + + /* Need to read VID early b/c it's used to differentiate CPQ and INTC + * discovery + */ + vendor_id = pdev->vendor; + if ((vendor_id != PCI_VENDOR_ID_COMPAQ) && + (vendor_id != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_non_compaq_or_intel); rc = -ENODEV; goto err_disable_device; } dbg("Vendor ID: %x\n", vendor_id); - rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - dbg("revision: %d\n", rev); - if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { + dbg("revision: %d\n", pdev->revision); + if ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!pdev->revision)) { err(msg_HPC_rev_error); rc = -ENODEV; goto err_disable_device; } - /* Check for the proper subsytem ID's - * Intel uses a different SSID programming model than Compaq. + /* Check for the proper subsystem IDs + * Intel uses a different SSID programming model than Compaq. * For Intel, each SSID bit identifies a PHP capability. - * Also Intel HPC's may have RID=0. + * Also Intel HPCs may have RID=0. */ - if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - // TODO: This code can be made to support non-Compaq or Intel subsystem IDs - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - goto err_disable_device; - } - dbg("Subsystem Vendor ID: %x\n", subsystem_vid); - if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { - err(msg_HPC_non_compaq_or_intel); - rc = -ENODEV; - goto err_disable_device; - } + if ((pdev->revision <= 2) && (vendor_id != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_not_supported); + return -ENODEV; + } - ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __FUNCTION__); - rc = -ENOMEM; - goto err_disable_device; - } - memset(ctrl, 0, sizeof(struct controller)); + /* TODO: This code can be made to support non-Compaq or Intel + * subsystem IDs + */ + subsystem_vid = pdev->subsystem_vendor; + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + rc = -ENODEV; + goto err_disable_device; + } - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - goto err_free_ctrl; - } + ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __func__); + rc = -ENOMEM; + goto err_disable_device; + } - info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - - /* Set Vendor ID, so it can be accessed later from other functions */ - ctrl->vendor_id = vendor_id; - - switch (subsystem_vid) { - case PCI_VENDOR_ID_COMPAQ: - if (rev >= 0x13) { /* CIOBX */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 1; - pci_read_config_byte(pdev, 0x41, &bus_cap); - if (bus_cap & 0x80) { - dbg("bus max supports 133MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; - break; - } - if (bus_cap & 0x40) { - dbg("bus max supports 100MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - break; - } - if (bus_cap & 20) { - dbg("bus max supports 66MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; - break; - } - if (bus_cap & 10) { - dbg("bus max supports 66MHz PCI\n"); - ctrl->speed_capability = PCI_SPEED_66MHz; - break; - } - - break; - } - - switch (subsystem_deviceid) { - case PCI_SUB_HPC_ID: - /* Original 6500/7000 implementation */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID2: - /* First Pushbutton implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID_INTC: - /* Third party (6500/7000) */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID3: - /* First 66 Mhz implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_66MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID4: - /* First PCI-X implementation, 100MHz */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 0; - break; - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - break; + subsystem_deviceid = pdev->subsystem_device; - case PCI_VENDOR_ID_INTEL: - /* Check for speed capability (0=33, 1=66) */ - if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = PCI_SPEED_66MHz; - } else { - ctrl->speed_capability = PCI_SPEED_33MHz; - } - - /* Check for push button */ - if (subsystem_deviceid & 0x0002) { - /* no push button */ - ctrl->push_button = 0; - } else { - /* push button supported */ - ctrl->push_button = 1; - } - - /* Check for slot switch type (0=mechanical, 1=not mechanical) */ - if (subsystem_deviceid & 0x0004) { - /* no switch */ - ctrl->slot_switch_type = 0; - } else { - /* switch */ - ctrl->slot_switch_type = 1; - } - - /* PHP Status (0=De-feature PHP, 1=Normal operation) */ - if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; // PHP supported - } else { - ctrl->defeature_PHP = 0; // PHP not supported - } - - /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; // supported - } else { - ctrl->alternate_base_address = 0; // not supported - } - - /* PCI Config Space Index (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; // supported - } else { - ctrl->pci_config_space = 0; // not supported - } - - /* PCI-X support */ - if (subsystem_deviceid & 0x0080) { - /* PCI-X capable */ - ctrl->pcix_support = 1; - /* Frequency of operation in PCI-X mode */ - if (subsystem_deviceid & 0x0040) { - /* 133MHz PCI-X if bit 7 is 1 */ - ctrl->pcix_speed_capability = 1; - } else { - /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ - /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ - ctrl->pcix_speed_capability = 0; - } - } else { - /* Conventional PCI */ - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - } + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other + * functions + */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + if (pdev->revision >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + bus->max_bus_speed = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + bus->max_bus_speed = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 0x20) { + dbg("bus max supports 66MHz PCI-X\n"); + bus->max_bus_speed = PCI_SPEED_66MHz_PCIX; break; + } + if (bus_cap & 0x10) { + dbg("bus max supports 66MHz PCI\n"); + bus->max_bus_speed = PCI_SPEED_66MHz; + break; + } - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; + break; } - } else { + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; + bus->max_bus_speed = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + bus->max_bus_speed = PCI_SPEED_33MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; + bus->max_bus_speed = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + bus->max_bus_speed = PCI_SPEED_66MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + bus->max_bus_speed = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 0; + break; + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) + bus->max_bus_speed = PCI_SPEED_66MHz; + else + bus->max_bus_speed = PCI_SPEED_33MHz; + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) + ctrl->push_button = 0; + else + ctrl->push_button = 1; + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) + ctrl->slot_switch_type = 0; + else + ctrl->slot_switch_type = 1; + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) + ctrl->defeature_PHP = 1; /* PHP supported */ + else + ctrl->defeature_PHP = 0; /* PHP not supported */ + + /* Alternate Base Address Register Interface + * (0=not supported, 1=supported) + */ + if (subsystem_deviceid & 0x0010) + ctrl->alternate_base_address = 1; + else + ctrl->alternate_base_address = 0; + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) + ctrl->pci_config_space = 1; + else + ctrl->pci_config_space = 0; + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + ctrl->pcix_support = 1; + if (subsystem_deviceid & 0x0040) + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + else + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: err(msg_HPC_not_supported); - return -ENODEV; + rc = -ENODEV; + goto err_free_ctrl; } - // Tell the user that we found one. + /* Tell the user that we found one. */ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); dbg("Hotplug controller capabilities:\n"); - dbg(" speed_capability %d\n", ctrl->speed_capability); + dbg(" speed_capability %d\n", bus->max_bus_speed); dbg(" slot_switch_type %s\n", ctrl->slot_switch_type ? "switch present" : "no switch"); dbg(" defeature_PHP %s\n", ctrl->defeature_PHP ? @@ -1056,20 +1079,19 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* make our own copy of the pci bus structure, * as we like tweaking it a lot */ - ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); + ctrl->pci_bus = kmemdup(pdev->bus, sizeof(*ctrl->pci_bus), GFP_KERNEL); if (!ctrl->pci_bus) { err("out of memory\n"); rc = -ENOMEM; goto err_free_ctrl; } - memcpy(ctrl->pci_bus, pdev->bus, sizeof(*ctrl->pci_bus)); ctrl->bus = pdev->bus->number; - ctrl->rev = rev; + ctrl->rev = pdev->revision; dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev); - init_MUTEX(&ctrl->crit_sect); + mutex_init(&ctrl->crit_sect); init_waitqueue_head(&ctrl->queue); /* initialize our threads if they haven't already been started up */ @@ -1077,10 +1099,10 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_free_bus; } - + dbg("pdev = %p\n", pdev); - dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); - dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); + dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0)); + dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0)); if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), MY_NAME)) { @@ -1092,15 +1114,15 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!ctrl->hpc_reg) { - err("cannot remap MMIO region %lx @ %lx\n", - pci_resource_len(pdev, 0), - pci_resource_start(pdev, 0)); + err("cannot remap MMIO region %llx @ %llx\n", + (unsigned long long)pci_resource_len(pdev, 0), + (unsigned long long)pci_resource_start(pdev, 0)); rc = -ENODEV; goto err_free_mem_region; } - // Check for 66Mhz operation - ctrl->speed = get_controller_speed(ctrl); + /* Check for 66Mhz operation */ + bus->cur_bus_speed = get_controller_speed(ctrl); /******************************************************** @@ -1110,7 +1132,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * ********************************************************/ - // find the physical slot number of the first hot plug slot + /* find the physical slot number of the first hot plug slot */ /* Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" @@ -1127,18 +1149,18 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_iounmap; } - // Store PCI Config Space for all devices on this bus + /* Store PCI Config Space for all devices on this bus */ rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); if (rc) { err("%s: unable to save PCI configuration data, error %d\n", - __FUNCTION__, rc); + __func__, rc); goto err_iounmap; } /* * Get IO, memory, and IRQ resources for new devices */ - // The next line is required for cpqhp_find_available_resources + /* The next line is required for cpqhp_find_available_resources */ ctrl->interrupt = pdev->irq; if (ctrl->interrupt < 0x10) { cpqhp_legacy_mode = 1; @@ -1169,29 +1191,31 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { err(msg_initialization_err, 6); err("%s: unable to save PCI configuration data, error %d\n", - __FUNCTION__, rc); + __func__, rc); goto err_iounmap; } - + /* Mask all general input interrupts */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); /* set up the interrupt */ dbg("HPC interrupt = %d \n", ctrl->interrupt); if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr, - SA_SHIRQ, MY_NAME, ctrl)) { + IRQF_SHARED, MY_NAME, ctrl)) { err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); rc = -ENODEV; goto err_iounmap; } - /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + /* Enable Shift Out interrupt and clear it, also enable SERR on power + * fault + */ temp_word = readw(ctrl->hpc_reg + MISC); temp_word |= 0x4006; writew(temp_word, ctrl->hpc_reg + MISC); - // Changed 05/05/97 to clear all interrupts at start + /* Changed 05/05/97 to clear all interrupts at start */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); @@ -1206,13 +1230,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) cpqhp_ctrl_list = ctrl; } - // turn off empty slots here unless command line option "ON" set - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); + /* turn off empty slots here unless command line option "ON" set + * Wait for exclusive access to hardware + */ + mutex_lock(&ctrl->crit_sect); num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // find first device number for the ctrl + /* find first device number for the ctrl */ device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; while (num_of_slots) { @@ -1224,23 +1249,21 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hp_slot = func->device - ctrl->slot_device_offset; dbg("hp_slot: %d\n", hp_slot); - // We have to save the presence info for these slots + /* We have to save the presence info for these slots */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) func->switch_save = 0; - } else { + else func->switch_save = 0x10; - } - if (!power_mode) { + if (!power_mode) if (!func->is_a_board) { green_LED_off(ctrl, hp_slot); slot_disable(ctrl, hp_slot); } - } device++; num_of_slots--; @@ -1248,21 +1271,21 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!power_mode) { set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); } rc = init_SERR(ctrl); if (rc) { err("init_SERR failed\n"); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); goto err_free_irq; } - // Done with exclusive hardware access - up(&ctrl->crit_sect); + /* Done with exclusive hardware access */ + mutex_unlock(&ctrl->crit_sect); - cpqhp_create_ctrl_files(ctrl); + cpqhp_create_debugfs_files(ctrl); return 0; @@ -1281,77 +1304,6 @@ err_disable_device: return rc; } - -static int one_time_init(void) -{ - int loop; - int retval = 0; - - if (initialized) - return 0; - - power_mode = 0; - - retval = pci_print_IRQ_route(); - if (retval) - goto error; - - dbg("Initialize + Start the notification mechanism \n"); - - retval = cpqhp_event_start_thread(); - if (retval) - goto error; - - dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { - cpqhp_slot_list[loop] = NULL; - } - - // FIXME: We also need to hook the NMI handler eventually. - // this also needs to be worked with Christoph - // register_NMI_handler(); - - // Map rom address - cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!cpqhp_rom_start) { - err ("Could not ioremap memory region for ROM\n"); - retval = -EIO; - goto error; - } - - /* Now, map the int15 entry point if we are on compaq specific hardware */ - compaq_nvram_init(cpqhp_rom_start); - - /* Map smbios table entry point structure */ - smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, - cpqhp_rom_start + ROM_PHY_LEN); - if (!smbios_table) { - err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO; - goto error_rom_start; - } - - smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), - readw(smbios_table + ST_LENGTH)); - if (!smbios_start) { - err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO; - goto error_smbios_start; - } - - initialized = 1; - - return retval; - -error_smbios_start: - iounmap(smbios_start); -error_rom_start: - iounmap(cpqhp_rom_start); -error: - return retval; -} - - static void __exit unload_cpqphpd(void) { struct pci_func *next; @@ -1371,10 +1323,10 @@ static void __exit unload_cpqphpd(void) if (ctrl->hpc_reg) { u16 misc; rc = read_slot_enable (ctrl); - + writeb(0, ctrl->hpc_reg + SLOT_SERR); writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); - + misc = readw(ctrl->hpc_reg + MISC); misc &= 0xFFFD; writew(misc, ctrl->hpc_reg + MISC); @@ -1454,38 +1406,34 @@ static void __exit unload_cpqphpd(void) } } - // Stop the notification mechanism + /* Stop the notification mechanism */ if (initialized) cpqhp_event_stop_thread(); - //unmap the rom address + /* unmap the rom address */ if (cpqhp_rom_start) iounmap(cpqhp_rom_start); if (smbios_start) iounmap(smbios_start); } - - static struct pci_device_id hpcd_pci_tbl[] = { { /* handle any PCI Hotplug controller */ .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), .class_mask = ~0, - + /* no matter who makes it */ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - + }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); - - static struct pci_driver cpqhpc_driver = { .name = "compaq_pci_hotplug", .id_table = hpcd_pci_tbl, @@ -1493,8 +1441,6 @@ static struct pci_driver cpqhpc_driver = { /* remove: cpqhpc_remove_one, */ }; - - static int __init cpqhpc_init(void) { int result; @@ -1502,12 +1448,12 @@ static int __init cpqhpc_init(void) cpqhp_debug = debug; info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + cpqhp_initialize_debugfs(); result = pci_register_driver(&cpqhpc_driver); dbg("pci_register_driver = %d\n", result); return result; } - static void __exit cpqhpc_cleanup(void) { dbg("unload_cpqphpd()\n"); @@ -1515,10 +1461,8 @@ static void __exit cpqhpc_cleanup(void) dbg("pci_unregister_driver\n"); pci_unregister_driver(&cpqhpc_driver); + cpqhp_shutdown_debugfs(); } - module_init(cpqhpc_init); module_exit(cpqhpc_cleanup); - - diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 10a5a7674a8..bde47fce324 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -26,7 +26,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> @@ -35,50 +34,37 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/wait.h> -#include <linux/smp_lock.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> +#include <linux/kthread.h> #include "cpqphp.h" -static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, u8 behind_bridge, struct resource_lists *resources); -static int configure_new_function(struct controller* ctrl, struct pci_func *func, +static int configure_new_function(struct controller *ctrl, struct pci_func *func, u8 behind_bridge, struct resource_lists *resources); static void interrupt_event_handler(struct controller *ctrl); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; +static struct task_struct *cpqhp_event_thread; +static unsigned long pushbutton_pending; /* = 0 */ /* delay is in jiffies to wait for */ static void long_delay(int delay) { - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around + /* + * XXX(hch): if someone is bored please convert all callers + * to call msleep_interruptible directly. They really want + * to specify timeouts in natural units and spend a lot of + * effort converting them to jiffies.. */ - down (&delay_sem); - - init_waitqueue_head(&delay_wait); - - add_wait_queue(&delay_wait, &wait); msleep_interruptible(jiffies_to_msecs(delay)); - remove_wait_queue(&delay_wait, &wait); - - up(&delay_sem); } /* FIXME: The following line needs to be somewhere else... */ #define WRONG_BUS_FREQUENCY 0x07 -static u8 handle_switch_change(u8 change, struct controller * ctrl) +static u8 handle_switch_change(u8 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -94,14 +80,15 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x1L << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); /* this is the structure that tells the worker thread - *what to do */ + * what to do + */ taskInfo = &(ctrl->event_queue[ctrl->next_event]); ctrl->next_event = (ctrl->next_event + 1) % 10; taskInfo->hp_slot = hp_slot; @@ -113,17 +100,17 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - /********************************** + /* * Switch opened - **********************************/ + */ func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; } else { - /********************************** + /* * Switch closed - **********************************/ + */ func->switch_save = 0x10; @@ -136,7 +123,7 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) } /** - * cpqhp_find_slot: find the struct slot of given device + * cpqhp_find_slot - find the struct slot of given device * @ctrl: scan lots of this controller * @device: the device id to find */ @@ -144,15 +131,14 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot = ctrl->slot; - while (slot && (slot->device != device)) { + while (slot && (slot->device != device)) slot = slot->next; - } return slot; } -static u8 handle_presence_change(u16 change, struct controller * ctrl) +static u8 handle_presence_change(u16 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -165,17 +151,17 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * Presence Change - **********************************/ + */ dbg("cpqsbd: Presence/Notify input change.\n"); dbg(" Changed bits are 0x%4.4x\n", change ); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x0101 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -190,22 +176,23 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) return 0; /* If the switch closed, must be a button - * If not in button mode, nevermind */ + * If not in button mode, nevermind + */ if (func->switch_save && (ctrl->push_button == 1)) { temp_word = ctrl->ctrl_int_comp >> 16; temp_byte = (temp_word >> hp_slot) & 0x01; temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; if (temp_byte != func->presence_save) { - /************************************** + /* * button Pressed (doesn't do anything) - **************************************/ + */ dbg("hp_slot %d button pressed\n", hp_slot); taskInfo->event_type = INT_BUTTON_PRESS; } else { - /********************************** + /* * button Released - TAKE ACTION!!!! - **********************************/ + */ dbg("hp_slot %d button released\n", hp_slot); taskInfo->event_type = INT_BUTTON_RELEASE; @@ -223,7 +210,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) } } else { /* Switch is open, assume a presence change - * Save the presence state */ + * Save the presence state + */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; @@ -244,7 +232,7 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) } -static u8 handle_power_fault(u8 change, struct controller * ctrl) +static u8 handle_power_fault(u8 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -254,17 +242,17 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * power fault - **********************************/ + */ info("power fault interrupt\n"); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x01 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -275,16 +263,16 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) rc++; if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { - /********************************** + /* * power fault Cleared - **********************************/ + */ func->status = 0x00; taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { - /********************************** + /* * power fault - **********************************/ + */ taskInfo->event_type = INT_POWER_FAULT; if (ctrl->rev < 4) { @@ -318,9 +306,8 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) /** - * sort_by_size: sort nodes on the list by their length, smallest first. + * sort_by_size - sort nodes on the list by their length, smallest first. * @head: list to sort - * */ static int sort_by_size(struct pci_resource **head) { @@ -367,9 +354,8 @@ static int sort_by_size(struct pci_resource **head) /** - * sort_by_max_size: sort nodes on the list by their length, largest first. + * sort_by_max_size - sort nodes on the list by their length, largest first. * @head: list to sort - * */ static int sort_by_max_size(struct pci_resource **head) { @@ -416,8 +402,10 @@ static int sort_by_max_size(struct pci_resource **head) /** - * do_pre_bridge_resource_split: find node of resources that are unused - * + * do_pre_bridge_resource_split - find node of resources that are unused + * @head: new list head + * @orig_head: original list head + * @alignment: max node size (?) */ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) @@ -445,13 +433,15 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front */ + * we may be able to split some off of the front + */ node = *head; if (node->length & (alignment -1)) { /* this one isn't an aligned length, so we'll make a new entry - * and split it up. */ + * and split it up. + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -490,8 +480,9 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h /** - * do_bridge_resource_split: find one node of resources that aren't in use - * + * do_bridge_resource_split - find one node of resources that aren't in use + * @head: list head + * @alignment: max node size (?) */ static struct pci_resource *do_bridge_resource_split(struct pci_resource **head, u32 alignment) { @@ -538,14 +529,13 @@ error: /** - * get_io_resource: find first node of given size not in ISA aliasing window. + * get_io_resource - find first node of given size not in ISA aliasing window. * @head: list to search * @size: size of node to find, must be a power of two. * - * Description: this function sorts the resource list by size and then returns + * Description: This function sorts the resource list by size and then returns * returns the first node of "size" length that is not in the ISA aliasing * window. If it finds a node larger than "size" it will split it up. - * */ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size) { @@ -557,10 +547,10 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (!(*head)) return NULL; - if ( cpqhp_resource_sort_and_combine(head) ) + if (cpqhp_resource_sort_and_combine(head)) return NULL; - if ( sort_by_size(head) ) + if (sort_by_size(head)) return NULL; for (node = *head; node; node = node->next) { @@ -569,7 +559,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (node->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -594,7 +585,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size /* Don't need to check if too small since we already did */ if (node->length > size) { /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -614,7 +606,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size continue; /* If we got here, then it is the right size - * Now take it out of the list and break */ + * Now take it out of the list and break + */ if (*head == node) { *head = node->next; } else { @@ -633,7 +626,7 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size /** - * get_max_resource: get largest node which has at least the given size. + * get_max_resource - get largest node which has at least the given size. * @head: the list to search the node in * @size: the minimum size of the node to find * @@ -655,14 +648,16 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz return NULL; for (max = *head; max; max = max->next) { - /* If not big enough we could probably just bail, - * instead we'll continue to the next. */ + /* If not big enough we could probably just bail, + * instead we'll continue to the next. + */ if (max->length < size) continue; if (max->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (max->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -685,7 +680,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz if ((max->base + max->length) & (size - 1)) { /* this one isn't end aligned properly at the top - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -713,7 +709,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz temp = temp->next; } - temp->next = max->next; + if (temp) + temp->next = max->next; } max->next = NULL; @@ -725,7 +722,7 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz /** - * get_resource: find resource of given size and split up larger ones. + * get_resource - find resource of given size and split up larger ones. * @head: the list to search for resources * @size: the size limit to use * @@ -750,14 +747,15 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) for (node = *head; node; node = node->next) { dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, node->base, node->length); + __func__, size, node, node->base, node->length); if (node->length < size) continue; if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); + dbg("%s: not aligned\n", __func__); /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -780,9 +778,10 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) /* Don't need to check if too small since we already did */ if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); + dbg("%s: too big\n", __func__); /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -797,7 +796,7 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) node->next = split_node; } /* End of too big on top end */ - dbg("%s: got one!!!\n", __FUNCTION__); + dbg("%s: got one!!!\n", __func__); /* If we got here, then it is the right size * Now take it out of the list */ if (*head == node) { @@ -817,14 +816,14 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) /** - * cpqhp_resource_sort_and_combine: sort nodes by base addresses and clean up. + * cpqhp_resource_sort_and_combine - sort nodes by base addresses and clean up * @head: the list to sort and clean up * * Description: Sorts all of the nodes in the list in ascending order by * their base addresses. Also does garbage collection by * combining adjacent nodes. * - * returns 0 if success + * Returns %0 if success. */ int cpqhp_resource_sort_and_combine(struct pci_resource **head) { @@ -832,7 +831,7 @@ int cpqhp_resource_sort_and_combine(struct pci_resource **head) struct pci_resource *node2; int out_of_order = 1; - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); + dbg("%s: head = %p, *head = %p\n", __func__, head, *head); if (!(*head)) return 1; @@ -890,7 +889,7 @@ int cpqhp_resource_sort_and_combine(struct pci_resource **head) } -irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) +irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) { struct controller *ctrl = data; u8 schedule_flag = 0; @@ -899,19 +898,19 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) u32 Diff; u32 temp_dword; - + misc = readw(ctrl->hpc_reg + MISC); - /*************************************** + /* * Check to see if it was our interrupt - ***************************************/ + */ if (!(misc & 0x000C)) { return IRQ_NONE; } if (misc & 0x0004) { - /********************************** + /* * Serial Output interrupt Pending - **********************************/ + */ /* Clear the interrupt */ misc |= 0x0004; @@ -920,7 +919,7 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) /* Read to clear posted writes */ misc = readw(ctrl->hpc_reg + MISC); - dbg ("%s - waking up\n", __FUNCTION__); + dbg ("%s - waking up\n", __func__); wake_up_interruptible(&ctrl->queue); } @@ -955,8 +954,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) } if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); + wake_up_process(cpqhp_event_thread); + dbg("Waking even thread"); } return IRQ_HANDLED; } @@ -964,24 +963,18 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) /** * cpqhp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located + * @busnumber: bus where new node is to be located * - * Returns pointer to the new node or NULL if unsuccessful + * Returns pointer to the new node or %NULL if unsuccessful. */ struct pci_func *cpqhp_slot_create(u8 busnumber) { struct pci_func *new_slot; struct pci_func *next; - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - - if (new_slot == NULL) { - /* I'm not dead yet! - * You will be. */ + new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); + if (new_slot == NULL) return new_slot; - } - - memset(new_slot, 0, sizeof(struct pci_func)); new_slot->next = NULL; new_slot->configured = 1; @@ -1002,9 +995,9 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) * slot_remove - Removes a node from the linked list of slots. * @old_slot: slot to remove * - * Returns 0 if successful, !0 otherwise. + * Returns %0 if successful, !0 otherwise. */ -static int slot_remove(struct pci_func * old_slot) +static int slot_remove(struct pci_func *old_slot) { struct pci_func *next; @@ -1012,10 +1005,8 @@ static int slot_remove(struct pci_func * old_slot) return 1; next = cpqhp_slot_list[old_slot->bus]; - - if (next == NULL) { + if (next == NULL) return 1; - } if (next == old_slot) { cpqhp_slot_list[old_slot->bus] = old_slot->next; @@ -1024,9 +1015,8 @@ static int slot_remove(struct pci_func * old_slot) return 0; } - while ((next->next != old_slot) && (next->next != NULL)) { + while ((next->next != old_slot) && (next->next != NULL)) next = next->next; - } if (next->next == old_slot) { next->next = old_slot->next; @@ -1042,7 +1032,7 @@ static int slot_remove(struct pci_func * old_slot) * bridge_slot_remove - Removes a node from the linked list of slots. * @bridge: bridge to remove * - * Returns 0 if successful, !0 otherwise. + * Returns %0 if successful, !0 otherwise. */ static int bridge_slot_remove(struct pci_func *bridge) { @@ -1056,9 +1046,8 @@ static int bridge_slot_remove(struct pci_func *bridge) for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { next = cpqhp_slot_list[tempBus]; - while (!slot_remove(next)) { + while (!slot_remove(next)) next = cpqhp_slot_list[tempBus]; - } } next = cpqhp_slot_list[bridge->bus]; @@ -1087,7 +1076,7 @@ out: * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed * @bus: bus to find * @device: device to find - * @index: is 0 for first function found, 1 for the second... + * @index: is %0 for first function found, %1 for the second... * * Returns pointer to the node if successful, %NULL otherwise. */ @@ -1120,7 +1109,7 @@ struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) /* DJZ: I don't think is_bridge will work as is. * FIXME */ -static int is_bridge(struct pci_func * func) +static int is_bridge(struct pci_func *func) { /* Check the header type */ if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) @@ -1131,81 +1120,83 @@ static int is_bridge(struct pci_func * func) /** - * set_controller_speed - set the frequency and/or mode of a specific - * controller segment. - * + * set_controller_speed - set the frequency and/or mode of a specific controller segment. * @ctrl: controller to change frequency/mode for. * @adapter_speed: the speed of the adapter we want to match. * @hp_slot: the slot number where the adapter is installed. * - * Returns 0 if we successfully change frequency and/or mode to match the + * Returns %0 if we successfully change frequency and/or mode to match the * adapter speed. - * */ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) { struct slot *slot; + struct pci_bus *bus = ctrl->pci_bus; u8 reg; u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); u16 reg16; u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); - - if (ctrl->speed == adapter_speed) + + if (bus->cur_bus_speed == adapter_speed) return 0; - + /* We don't allow freq/mode changes if we find another adapter running - * in another slot on this controller */ + * in another slot on this controller + */ for(slot = ctrl->slot; slot; slot = slot->next) { - if (slot->device == (hp_slot + ctrl->slot_device_offset)) + if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; - if (!slot->hotplug_slot && !slot->hotplug_slot->info) + if (!slot->hotplug_slot || !slot->hotplug_slot->info) continue; - if (slot->hotplug_slot->info->adapter_status == 0) + if (slot->hotplug_slot->info->adapter_status == 0) continue; /* If another adapter is running on the same segment but at a * lower speed/mode, we allow the new adapter to function at - * this rate if supported */ - if (ctrl->speed < adapter_speed) + * this rate if supported + */ + if (bus->cur_bus_speed < adapter_speed) return 0; return 1; } - + /* If the controller doesn't support freq/mode changes and the - * controller is running at a higher mode, we bail */ - if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) + * controller is running at a higher mode, we bail + */ + if ((bus->cur_bus_speed > adapter_speed) && (!ctrl->pcix_speed_capability)) return 1; - + /* But we allow the adapter to run at a lower rate if possible */ - if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) + if ((bus->cur_bus_speed < adapter_speed) && (!ctrl->pcix_speed_capability)) return 0; /* We try to set the max speed supported by both the adapter and - * controller */ - if (ctrl->speed_capability < adapter_speed) { - if (ctrl->speed == ctrl->speed_capability) + * controller + */ + if (bus->max_bus_speed < adapter_speed) { + if (bus->cur_bus_speed == bus->max_bus_speed) return 0; - adapter_speed = ctrl->speed_capability; + adapter_speed = bus->max_bus_speed; } writel(0x0L, ctrl->hpc_reg + LED_CONTROL); writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); + + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); - + if (adapter_speed != PCI_SPEED_133MHz_PCIX) reg = 0xF5; else - reg = 0xF4; + reg = 0xF4; pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); reg16 &= ~0x000F; switch(adapter_speed) { - case(PCI_SPEED_133MHz_PCIX): + case(PCI_SPEED_133MHz_PCIX): reg = 0x75; - reg16 |= 0xB; + reg16 |= 0xB; break; case(PCI_SPEED_100MHz_PCIX): reg = 0x74; @@ -1222,84 +1213,84 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ default: /* 33MHz PCI 2.2 */ reg = 0x71; break; - + } reg16 |= 0xB << 12; writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); - - mdelay(5); - + + mdelay(5); + /* Reenable interrupts */ writel(0, ctrl->hpc_reg + INT_MASK); - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + /* Restart state machine */ reg = ~0xF; pci_read_config_byte(ctrl->pci_dev, 0x43, ®); pci_write_config_byte(ctrl->pci_dev, 0x43, reg); - + /* Only if mode change...*/ - if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || - ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) + if (((bus->cur_bus_speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || + ((bus->cur_bus_speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) set_SOGO(ctrl); - + wait_for_ctrl_irq(ctrl); mdelay(1100); - + /* Restore LED/Slot state */ writel(leds, ctrl->hpc_reg + LED_CONTROL); writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); - + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); - ctrl->speed = adapter_speed; + bus->cur_bus_speed = adapter_speed; slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - info("Successfully changed frequency/mode for adapter in slot %d\n", + info("Successfully changed frequency/mode for adapter in slot %d\n", slot->number); return 0; } -/* the following routines constitute the bulk of the - hotplug controller logic +/* the following routines constitute the bulk of the + * hotplug controller logic */ /** * board_replaced - Called after a board has been replaced in the system. + * @func: PCI device/function information + * @ctrl: hotplug controller * - * This is only used if we don't have resources for hot add - * Turns power on for the board - * Checks to see if board is the same - * If board is same, reconfigures it + * This is only used if we don't have resources for hot add. + * Turns power on for the board. + * Checks to see if board is the same. + * If board is same, reconfigures it. * If board isn't same, turns it back off. - * */ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) { + struct pci_bus *bus = ctrl->pci_bus; u8 hp_slot; u8 temp_byte; u8 adapter_speed; - u32 index; u32 rc = 0; - u32 src = 8; hp_slot = func->device - ctrl->slot_device_offset; - if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - /********************************** - * The switch is open. - **********************************/ + /* + * The switch is open. + */ + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) rc = INTERLOCK_OPEN; - } else if (is_slot_enabled (ctrl, hp_slot)) { - /********************************** - * The board is already on - **********************************/ + /* + * The board is already on + */ + else if (is_slot_enabled (ctrl, hp_slot)) rc = CARD_FUNCTIONING; - } else { - down(&ctrl->crit_sect); + else { + mutex_lock(&ctrl->crit_sect); /* turn on board without attaching to the bus */ enable_slot_power (ctrl, hp_slot); @@ -1319,9 +1310,9 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) + if (bus->cur_bus_speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; @@ -1333,12 +1324,12 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); if (rc) return rc; - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); slot_enable (ctrl, hp_slot); green_LED_blink (ctrl, hp_slot); @@ -1350,7 +1341,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); /* Wait for ~1 second because of hot plug spec */ long_delay(1*HZ); @@ -1368,84 +1359,40 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) rc = cpqhp_configure_board(ctrl, func); - if (rc || src) { - /* If configuration fails, turn it off - * Get slot won't work for devices behind - * bridges, but in this case it will always be - * called for the "base" bus/dev/func of an - * adapter. */ - - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - /* Wait for SOBS to be unset */ - wait_for_ctrl_irq (ctrl); - - up(&ctrl->crit_sect); - - if (rc) - return rc; - else - return 1; - } - - func->status = 0; - func->switch_save = 0x10; - - index = 1; - while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { - rc |= cpqhp_configure_board(ctrl, func); - index++; - } - - if (rc) { - /* If configuration fails, turn it off - * Get slot won't work for devices behind - * bridges, but in this case it will always be - * called for the "base" bus/dev/func of an - * adapter. */ - - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); + /* If configuration fails, turn it off + * Get slot won't work for devices behind + * bridges, but in this case it will always be + * called for the "base" bus/dev/func of an + * adapter. + */ - /* Wait for SOBS to be unset */ - wait_for_ctrl_irq (ctrl); - - up(&ctrl->crit_sect); - - return rc; - } - /* Done configuring so turn LED on full time */ + mutex_lock(&ctrl->crit_sect); - down(&ctrl->crit_sect); - - green_LED_on (ctrl, hp_slot); + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); set_SOGO(ctrl); /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); - rc = 0; + mutex_unlock(&ctrl->crit_sect); + + if (rc) + return rc; + else + return 1; + } else { /* Something is wrong * Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" - * bus/dev/func of an adapter. */ + * bus/dev/func of an adapter. + */ - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); amber_LED_on (ctrl, hp_slot); green_LED_off (ctrl, hp_slot); @@ -1456,7 +1403,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); } } @@ -1467,10 +1414,11 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /** * board_added - Called after a board has been added to the system. + * @func: PCI device/function info + * @ctrl: hotplug controller * - * Turns power on for the board - * Configures board - * + * Turns power on for the board. + * Configures board. */ static u32 board_added(struct pci_func *func, struct controller *ctrl) { @@ -1481,14 +1429,15 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) u32 temp_register = 0xFFFFFFFF; u32 rc = 0; struct pci_func *new_slot = NULL; + struct pci_bus *bus = ctrl->pci_bus; struct slot *p_slot; struct resource_lists res_lists; hp_slot = func->device - ctrl->slot_device_offset; dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", - __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + __func__, func->device, ctrl->slot_device_offset, hp_slot); - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); /* turn on board without attaching to the bus */ enable_slot_power(ctrl, hp_slot); @@ -1499,7 +1448,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) wait_for_ctrl_irq (ctrl); /* Change bits in slot power register to force another shift out - * NOTE: this is to work around the timer bug */ + * NOTE: this is to work around the timer bug + */ temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); writeb(0x00, ctrl->hpc_reg + SLOT_POWER); writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); @@ -1508,12 +1458,12 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) + if (bus->cur_bus_speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; - + /* turn off board without attaching to the bus */ disable_slot_power (ctrl, hp_slot); @@ -1522,71 +1472,71 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); if (rc) return rc; - + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); /* turn on board and blink green LED */ - dbg("%s: before down\n", __FUNCTION__); - down(&ctrl->crit_sect); - dbg("%s: after down\n", __FUNCTION__); + dbg("%s: before down\n", __func__); + mutex_lock(&ctrl->crit_sect); + dbg("%s: after down\n", __func__); - dbg("%s: before slot_enable\n", __FUNCTION__); + dbg("%s: before slot_enable\n", __func__); slot_enable (ctrl, hp_slot); - dbg("%s: before green_LED_blink\n", __FUNCTION__); + dbg("%s: before green_LED_blink\n", __func__); green_LED_blink (ctrl, hp_slot); - dbg("%s: before amber_LED_blink\n", __FUNCTION__); + dbg("%s: before amber_LED_blink\n", __func__); amber_LED_off (ctrl, hp_slot); - dbg("%s: before set_SOGO\n", __FUNCTION__); + dbg("%s: before set_SOGO\n", __func__); set_SOGO(ctrl); /* Wait for SOBS to be unset */ - dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__); + dbg("%s: before wait_for_ctrl_irq\n", __func__); wait_for_ctrl_irq (ctrl); - dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__); + dbg("%s: after wait_for_ctrl_irq\n", __func__); - dbg("%s: before up\n", __FUNCTION__); - up(&ctrl->crit_sect); - dbg("%s: after up\n", __FUNCTION__); + dbg("%s: before up\n", __func__); + mutex_unlock(&ctrl->crit_sect); + dbg("%s: after up\n", __func__); /* Wait for ~1 second because of hot plug spec */ - dbg("%s: before long_delay\n", __FUNCTION__); + dbg("%s: before long_delay\n", __func__); long_delay(1*HZ); - dbg("%s: after long_delay\n", __FUNCTION__); + dbg("%s: after long_delay\n", __func__); - dbg("%s: func status = %x\n", __FUNCTION__, func->status); + dbg("%s: func status = %x\n", __func__, func->status); /* Check for a power fault */ if (func->status == 0xFF) { /* power fault occurred, but it was benign */ temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + dbg("%s: temp register set to %x by power fault\n", __func__, temp_register); rc = POWER_FAILURE; func->status = 0; } else { /* Get vendor/device ID u32 */ ctrl->pci_bus->number = func->bus; rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); + dbg("%s: pci_read_config_dword returns %d\n", __func__, rc); + dbg("%s: temp_register is %x\n", __func__, temp_register); if (rc != 0) { /* Something's wrong here */ temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); + dbg("%s: temp register set to %x by error\n", __func__, temp_register); } /* Preset return code. It will be changed later if things go okay. */ rc = NO_ADAPTER_PRESENT; } /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ + if (temp_register != 0xFFFFFFFF) { res_lists.io_head = ctrl->io_head; res_lists.mem_head = ctrl->mem_head; res_lists.p_mem_head = ctrl->p_mem_head; @@ -1595,7 +1545,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) rc = configure_new_device(ctrl, func, 0, &res_lists); - dbg("%s: back from configure_new_device\n", __FUNCTION__); + dbg("%s: back from configure_new_device\n", __func__); ctrl->io_head = res_lists.io_head; ctrl->mem_head = res_lists.mem_head; ctrl->p_mem_head = res_lists.p_mem_head; @@ -1607,7 +1557,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); if (rc) { - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); amber_LED_on (ctrl, hp_slot); green_LED_off (ctrl, hp_slot); @@ -1618,7 +1568,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); return rc; } else { cpqhp_save_slot_config(ctrl, func); @@ -1631,16 +1581,15 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* next, we will instantiate the linux pci_dev structures (with * appropriate driver notification, if already present) */ - dbg("%s: configure linux pci_dev structure\n", __FUNCTION__); + dbg("%s: configure linux pci_dev structure\n", __func__); index = 0; do { new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); - if (new_slot && !new_slot->pci_dev) { + if (new_slot && !new_slot->pci_dev) cpqhp_configure_device(ctrl, new_slot); - } } while (new_slot); - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); green_LED_on (ctrl, hp_slot); @@ -1649,9 +1598,9 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); } else { - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); amber_LED_on (ctrl, hp_slot); green_LED_off (ctrl, hp_slot); @@ -1662,7 +1611,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); return rc; } @@ -1671,10 +1620,12 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /** - * remove_board - Turns off slot and LED's - * + * remove_board - Turns off slot and LEDs + * @func: PCI device/function info + * @replace_flag: whether replacing or adding a new device + * @ctrl: target controller */ -static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +static u32 remove_board(struct pci_func *func, u32 replace_flag, struct controller *ctrl) { int index; u8 skip = 0; @@ -1691,7 +1642,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control device = func->device; hp_slot = func->device - ctrl->slot_device_offset; - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + dbg("In %s, hp_slot = %d\n", __func__, hp_slot); /* When we get here, it is safe to change base address registers. * We will attempt to save the base address register lengths */ @@ -1721,7 +1672,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control func->status = 0x01; func->configured = 0; - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); green_LED_off (ctrl, hp_slot); slot_disable (ctrl, hp_slot); @@ -1736,7 +1687,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); if (!replace_flag && ctrl->add_support) { while (func) { @@ -1786,24 +1737,22 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control static void pushbutton_helper_thread(unsigned long data) { pushbutton_pending = data; - up(&event_semaphore); + wake_up_process(cpqhp_event_thread); } /* this is the main worker thread */ -static int event_thread(void* data) +static int event_thread(void *data) { struct controller *ctrl; - lock_kernel(); - daemonize("phpd_event"); - - unlock_kernel(); while (1) { dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; /* Do stuff here */ if (pushbutton_pending) cpqhp_pushbutton_thread(pushbutton_pending); @@ -1812,38 +1761,24 @@ static int event_thread(void* data) interrupt_event_handler(ctrl); } dbg("event_thread signals exit\n"); - up(&event_exit); return 0; } - int cpqhp_event_start_thread(void) { - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, NULL, 0); - if (pid < 0) { + cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event"); + if (IS_ERR(cpqhp_event_thread)) { err ("Can't start up our event thread\n"); - return -1; + return PTR_ERR(cpqhp_event_thread); } - dbg("Our event thread pid = %d\n", pid); + return 0; } void cpqhp_event_stop_thread(void) { - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); + kthread_stop(cpqhp_event_thread); } @@ -1894,12 +1829,12 @@ static void interrupt_event_handler(struct controller *ctrl) if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { dbg("button pressed\n"); - } else if (ctrl->event_queue[loop].event_type == + } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { dbg("button cancel\n"); del_timer(&p_slot->task_event); - down(&ctrl->crit_sect); + mutex_lock(&ctrl->crit_sect); if (p_slot->state == BLINKINGOFF_STATE) { /* slot is on */ @@ -1922,7 +1857,7 @@ static void interrupt_event_handler(struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); } /*** button Released (No action on press...) */ else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { @@ -1937,19 +1872,19 @@ static void interrupt_event_handler(struct controller *ctrl) p_slot->state = BLINKINGON_STATE; info(msg_button_on, p_slot->number); } - down(&ctrl->crit_sect); - + mutex_lock(&ctrl->crit_sect); + dbg("blink green LED and turn off amber\n"); - + amber_LED_off (ctrl, hp_slot); green_LED_blink (ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - up(&ctrl->crit_sect); + mutex_unlock(&ctrl->crit_sect); init_timer(&p_slot->task_event); p_slot->hp_slot = hp_slot; p_slot->ctrl = ctrl; @@ -1966,8 +1901,7 @@ static void interrupt_event_handler(struct controller *ctrl) dbg("power fault\n"); } else { /* refresh notification */ - if (p_slot) - update_slot_info(ctrl, p_slot); + update_slot_info(ctrl, p_slot); } ctrl->event_queue[loop].event_type = 0; @@ -1982,11 +1916,11 @@ static void interrupt_event_handler(struct controller *ctrl) /** - * cpqhp_pushbutton_thread + * cpqhp_pushbutton_thread - handle pushbutton events + * @slot: target slot (struct) * - * Scheduled procedure to handle blocking stuff for the pushbuttons + * Scheduled procedure to handle blocking stuff for the pushbuttons. * Handles all pending events and exits. - * */ void cpqhp_pushbutton_thread(unsigned long slot) { @@ -2007,20 +1941,18 @@ void cpqhp_pushbutton_thread(unsigned long slot) func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); + dbg("Error! func NULL in %s\n", __func__); return ; } - if (func != NULL && ctrl != NULL) { - if (cpqhp_process_SS(ctrl, func) != 0) { - amber_LED_on (ctrl, hp_slot); - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); + if (cpqhp_process_SS(ctrl, func) != 0) { + amber_LED_on(ctrl, hp_slot); + green_LED_on(ctrl, hp_slot); - /* Wait for SOBS to be unset */ - wait_for_ctrl_irq (ctrl); - } + set_SOGO(ctrl); + + /* Wait for SOBS to be unset */ + wait_for_ctrl_irq(ctrl); } p_slot->state = STATIC_STATE; @@ -2031,15 +1963,15 @@ void cpqhp_pushbutton_thread(unsigned long slot) func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); + dbg("Error! func NULL in %s\n", __func__); return ; } - if (func != NULL && ctrl != NULL) { + if (ctrl != NULL) { if (cpqhp_process_SI(ctrl, func) != 0) { amber_LED_on(ctrl, hp_slot); green_LED_off(ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ @@ -2060,7 +1992,7 @@ int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func) u16 temp_word; u32 tempdword; int rc; - struct slot* p_slot; + struct slot *p_slot; int physical_slot = 0; tempdword = 0; @@ -2139,7 +2071,7 @@ int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func) } if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); + dbg("%s: rc = %d\n", __func__, rc); } if (p_slot) @@ -2156,11 +2088,11 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) u8 replace_flag; u32 rc = 0; unsigned int devfn; - struct slot* p_slot; + struct slot *p_slot; struct pci_bus *pci_bus = ctrl->pci_bus; int physical_slot=0; - device = func->device; + device = func->device; func = cpqhp_slot_find(ctrl->bus, device, index++); p_slot = cpqhp_find_slot(ctrl, device); if (p_slot) { @@ -2194,9 +2126,8 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) /* If the VGA Enable bit is set, remove isn't * supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { + if (BCR & PCI_BRIDGE_CTL_VGA) rc = REMOVE_NOT_SUPPORTED; - } } } @@ -2219,9 +2150,10 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) } /** - * switch_leds: switch the leds, go from one site to the other. + * switch_leds - switch the leds, go from one site to the other. * @ctrl: controller to use * @num_of_slots: number of slots to use + * @work_LED: LED control value * @direction: 1 to start from the left side, 0 to start right. */ static void switch_leds(struct controller *ctrl, const int num_of_slots, @@ -2247,11 +2179,11 @@ static void switch_leds(struct controller *ctrl, const int num_of_slots, } /** - * hardware_test - runs hardware tests + * cpqhp_hardware_test - runs hardware tests + * @ctrl: target controller + * @test_num: the number written to the "test" file in sysfs. * * For hot plug ctrl folks to play with. - * test_num is the number written to the "test" file in sysfs - * */ int cpqhp_hardware_test(struct controller *ctrl, int test_num) { @@ -2263,67 +2195,67 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; switch (test_num) { - case 1: - /* Do stuff here! */ - - /* Do that funky LED thing */ - /* so we can restore them later */ - save_LED = readl(ctrl->hpc_reg + LED_CONTROL); - work_LED = 0x01010101; - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - work_LED = 0x00000101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); + case 1: + /* Do stuff here! */ + + /* Do that funky LED thing */ + /* so we can restore them later */ + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); + work_LED = 0x01010101; + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); + /* Wait for SOGO interrupt */ + wait_for_ctrl_irq (ctrl); - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED >> 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); + set_SOGO(ctrl); - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); + /* Wait for SOGO interrupt */ + wait_for_ctrl_irq (ctrl); - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED << 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - } + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } - /* put it back the way it was */ - writel(save_LED, ctrl->hpc_reg + LED_CONTROL); + /* put it back the way it was */ + writel(save_LED, ctrl->hpc_reg + LED_CONTROL); - set_SOGO(ctrl); + set_SOGO(ctrl); - /* Wait for SOBS to be unset */ - wait_for_ctrl_irq (ctrl); - break; - case 2: - /* Do other stuff here! */ - break; - case 3: - /* and more... */ - break; + /* Wait for SOBS to be unset */ + wait_for_ctrl_irq (ctrl); + break; + case 2: + /* Do other stuff here! */ + break; + case 3: + /* and more... */ + break; } return 0; } @@ -2331,17 +2263,15 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) /** * configure_new_device - Configures the PCI header information of one board. - * * @ctrl: pointer to controller structure * @func: pointer to function structure * @behind_bridge: 1 if this is a recursive call, 0 if not * @resources: pointer to set of resource lists * - * Returns 0 if success - * + * Returns 0 if success. */ -static u32 configure_new_device(struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources) { u8 temp_byte, function, max_functions, stop_it; int rc; @@ -2351,12 +2281,12 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func new_slot = func; - dbg("%s\n", __FUNCTION__); + dbg("%s\n", __func__); /* Check for Multi-function device */ ctrl->pci_bus->number = func->bus; rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); + dbg("%s: rc = %d\n", __func__, rc); return rc; } @@ -2394,9 +2324,9 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func while ((function < max_functions) && (!stop_it)) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ + if (ID == 0xFFFFFFFF) { function++; - } else { /* There's something there */ + } else { /* Setup slot structure. */ new_slot = cpqhp_slot_create(func->bus); @@ -2421,22 +2351,20 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func /* - Configuration logic that involves the hotplug data structures and - their bookkeeping + * Configuration logic that involves the hotplug data structures and + * their bookkeeping */ /** * configure_new_function - Configures the PCI header information of one device - * * @ctrl: pointer to controller structure * @func: pointer to function structure * @behind_bridge: 1 if this is a recursive call, 0 if not * @resources: pointer to set of resource lists * * Calls itself recursively for bridged devices. - * Returns 0 if success - * + * Returns 0 if success. */ static int configure_new_function(struct controller *ctrl, struct pci_func *func, u8 behind_bridge, @@ -2477,18 +2405,18 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func if (rc) return rc; - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* set Primary bus */ dbg("set Primary bus = %d\n", func->bus); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); if (rc) return rc; - /* find range of busses to use */ + /* find range of buses to use */ dbg("find ranges of buses to use\n"); bus_node = get_max_resource(&(resources->bus_head), 1); - /* If we don't have any busses to allocate, we can't continue */ + /* If we don't have any buses to allocate, we can't continue */ if (!bus_node) return -ENOMEM; @@ -2568,7 +2496,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func temp_resources.irqs = &irqs; /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources */ + * if there is a problem,we can just use these to free resources + */ hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); @@ -2591,70 +2520,41 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func /* If we have IO resources copy them and fill in the bridge's * IO range registers */ - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - /* set IO base and Limit registers */ - temp_byte = io_node->base >> 8; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; - temp_byte = (io_node->base + io_node->length - 1) >> 8; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } + /* set IO base and Limit registers */ + temp_byte = io_node->base >> 8; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); - /* If we have memory resources copy them and fill in the - * bridge's memory range registers. Otherwise, fill in the - * range registers with values that disable them. */ - if (mem_node) { - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - /* set Mem base and Limit registers */ - temp_word = mem_node->base >> 16; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = (mem_node->base + mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - kfree(hold_mem_node); - hold_mem_node = NULL; - } + /* Copy the memory resources and fill in the bridge's memory + * range registers. + */ + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; - /* If we have prefetchable memory resources copy them and - * fill in the bridge's memory range registers. Otherwise, - * fill in the range registers with values that disable them. */ - if (p_mem_node) { - memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); - p_mem_node->next = NULL; + /* set Mem base and Limit registers */ + temp_word = mem_node->base >> 16; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - /* set Pre Mem base and Limit registers */ - temp_word = p_mem_node->base >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + /* set Pre Mem base and Limit registers */ + temp_word = p_mem_node->base >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - kfree(hold_p_mem_node); - hold_p_mem_node = NULL; - } + temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - /* Adjust this to compensate for extra adjustment in first loop */ + /* Adjust this to compensate for extra adjustment in first loop + */ irqs.barber_pole--; rc = 0; @@ -2702,7 +2602,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func for (cloop = 0; cloop < 4; cloop++) { if (irqs.valid_INT & (0x01 << cloop)) { rc = cpqhp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); + cloop + 1, irqs.interrupt[cloop]); if (rc) goto free_and_out; } @@ -2711,7 +2611,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func /* Return unused bus resources * First use the temporary node to store information for * the board */ - if (hold_bus_node && bus_node && temp_resources.bus_head) { + if (bus_node && temp_resources.bus_head) { hold_bus_node->length = bus_node->base - hold_bus_node->base; hold_bus_node->next = func->bus_head; @@ -2835,7 +2735,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } /* If we have prefetchable memory space available and there * is some left at the end, return the unused portion */ - if (hold_p_mem_node && temp_resources.p_mem_head) { + if (temp_resources.p_mem_head) { p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), &hold_p_mem_node, 0x100000); @@ -2974,27 +2874,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func func->mem_head = mem_node; } else return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x04) { - /* Map memory */ - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - mem_node = get_resource(&(resources->mem_head), base); - - /* allocate the resource to the board */ - if (mem_node) { - base = mem_node->base; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x06) { - /* Those bits are reserved, we can't handle this */ - return 1; } else { - /* Requesting space below 1M */ + /* Reserved bits or requesting space below 1M */ return NOT_ENOUGH_RESOURCES; } @@ -3015,27 +2896,26 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } /* End of base register loop */ if (cpqhp_legacy_mode) { /* Figure out which interrupt pin this function uses */ - rc = pci_bus_read_config_byte (pci_bus, devfn, + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); /* If this function needs an interrupt and we are behind * a bridge and the pin is tied to something that's - * alread mapped, set this one the same */ - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & + * already mapped, set this one the same */ + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { /* We have to share with something already set up */ - IRQ = resources->irqs->interrupt[(temp_byte + + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; } else { /* Program IRQ based on card type */ rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (class_code == PCI_BASE_CLASS_STORAGE) { + if (class_code == PCI_BASE_CLASS_STORAGE) IRQ = cpqhp_disk_irq; - } else { + else IRQ = cpqhp_nic_irq; - } } /* IRQ Line */ @@ -3043,7 +2923,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } if (!behind_bridge) { - rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + rc = cpqhp_set_irq(func->bus, func->device, temp_byte, IRQ); if (rc) return 1; } else { diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index ac98a11bd1e..0968a9bcb34 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -26,7 +26,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> @@ -34,7 +33,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/pci.h> -#include <linux/init.h> +#include <linux/pci_hotplug.h> #include <asm/uaccess.h> #include "cpqphp.h" #include "cpqphp_nvram.h" @@ -94,12 +93,13 @@ static u8 evbuffer[1024]; static void __iomem *compaq_int15_entry_point; -static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ +/* lock for ordering int15_bios_call() */ +static spinlock_t int15_lock; /* This is a series of function that deals with - setting & getting the hotplug resource table in some environment variable. -*/ + * setting & getting the hotplug resource table in some environment variable. + */ /* * We really shouldn't be doing this unless there is a _very_ good reason to!!! @@ -107,13 +107,13 @@ static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ */ -static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail) { u8 **tByte; if ((*used + 1) > *avail) return(1); - + *((u8*)*p_buffer) = value; tByte = (u8**)p_buffer; (*tByte)++; @@ -122,7 +122,7 @@ static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) } -static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail) { if ((*used + 4) > *avail) return(1); @@ -160,7 +160,7 @@ static int check_for_compaq_ROM (void __iomem *rom_start) (temp6 == 'Q')) { result = 1; } - dbg ("%s - returned %d\n", __FUNCTION__, result); + dbg ("%s - returned %d\n", __func__, result); return result; } @@ -170,10 +170,10 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) unsigned long flags; int op = operation; int ret_val; - + if (!compaq_int15_entry_point) return -ENODEV; - + spin_lock_irqsave(&int15_lock, flags); __asm__ ( "xorl %%ebx,%%ebx\n" \ @@ -187,7 +187,7 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) "D" (buffer), "m" (compaq_int15_entry_point) : "%ebx", "%edx"); spin_unlock_irqrestore(&int15_lock, flags); - + return((ret_val & 0xFF00) >> 8); } @@ -210,14 +210,16 @@ static int load_HRT (void __iomem *rom_start) available = 1024; - // Now load the EV + /* Now load the EV */ temp_dword = available; rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); evbuffer_length = temp_dword; - // We're maintaining the resource lists so write FF to invalidate old info + /* We're maintaining the resource lists so write FF to invalidate old + * info + */ temp_dword = 1; rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); @@ -263,14 +265,14 @@ static u32 store_HRT (void __iomem *rom_start) p_EV_header = (struct ev_hrt_header *) pFill; ctrl = cpqhp_ctrl_list; - - // The revision of this structure - rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + + /* The revision of this structure */ + rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available); if (rc) return(rc); - // The number of controllers - rc = add_byte( &pFill, 1, &usedbytes, &available); + /* The number of controllers */ + rc = add_byte(&pFill, 1, &usedbytes, &available); if (rc) return(rc); @@ -279,27 +281,27 @@ static u32 store_HRT (void __iomem *rom_start) numCtrl++; - // The bus number - rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + /* The bus number */ + rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available); if (rc) return(rc); - // The device Number - rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); + /* The device Number */ + rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // The function Number - rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); + /* The function Number */ + rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // Skip the number of available entries - rc = add_dword( &pFill, 0, &usedbytes, &available); + /* Skip the number of available entries */ + rc = add_dword(&pFill, 0, &usedbytes, &available); if (rc) return(rc); - // Figure out memory Available + /* Figure out memory Available */ resNode = ctrl->mem_head; @@ -308,23 +310,23 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + /* base */ + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + /* length */ + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->mem_avail = loop; - // Figure out prefetchable memory Available + /* Figure out prefetchable memory Available */ resNode = ctrl->p_mem_head; @@ -333,23 +335,23 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + /* base */ + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + /* length */ + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->p_mem_avail = loop; - // Figure out IO Available + /* Figure out IO Available */ resNode = ctrl->io_head; @@ -358,23 +360,23 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + /* base */ + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + /* length */ + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->io_avail = loop; - // Figure out bus Available + /* Figure out bus Available */ resNode = ctrl->bus_head; @@ -383,28 +385,28 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + /* base */ + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + /* length */ + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->bus_avail = loop; ctrl = ctrl->next; } - + p_EV_header->num_of_ctrl = numCtrl; - // Now store the EV + /* Now store the EV */ temp_dword = usedbytes; @@ -449,20 +451,21 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) struct ev_hrt_header *p_EV_header; if (!evbuffer_init) { - // Read the resource list information in from NVRAM + /* Read the resource list information in from NVRAM */ if (load_HRT(rom_start)) memset (evbuffer, 0, 1024); evbuffer_init = 1; } - // If we saved information in NVRAM, use it now + /* If we saved information in NVRAM, use it now */ p_EV_header = (struct ev_hrt_header *) evbuffer; - // The following code is for systems where version 1.0 of this - // driver has been loaded, but doesn't support the hardware. - // In that case, the driver would incorrectly store something - // in NVRAM. + /* The following code is for systems where version 1.0 of this + * driver has been loaded, but doesn't support the hardware. + * In that case, the driver would incorrectly store something + * in NVRAM. + */ if ((p_EV_header->Version == 2) || ((p_EV_header->Version == 1) && !ctrl->push_flag)) { p_byte = &(p_EV_header->next); @@ -479,7 +482,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) function = p_ev_ctrl->function; while ((bus != ctrl->bus) || - (device != PCI_SLOT(ctrl->pci_dev->devfn)) || + (device != PCI_SLOT(ctrl->pci_dev->devfn)) || (function != PCI_FUNC(ctrl->pci_dev->devfn))) { nummem = p_ev_ctrl->mem_avail; numpmem = p_ev_ctrl->p_mem_avail; @@ -491,7 +494,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (p_byte > ((u8*)p_EV_header + evbuffer_length)) return 2; - // Skip forward to the next entry + /* Skip forward to the next entry */ p_byte += (nummem + numpmem + numio + numbus) * 8; if (p_byte > ((u8*)p_EV_header + evbuffer_length)) @@ -520,7 +523,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) return 2; while (nummem--) { - mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); if (!mem_node) break; @@ -548,7 +551,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) } while (numpmem--) { - p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); if (!p_mem_node) break; @@ -576,7 +579,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) } while (numio--) { - io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); if (!io_node) break; @@ -604,7 +607,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) } while (numbus--) { - bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); if (!bus_node) break; @@ -629,8 +632,9 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) ctrl->bus_head = bus_node; } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); @@ -640,14 +644,14 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (rc) return(rc); } else { - if ((evbuffer[0] != 0) && (!ctrl->push_flag)) + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) return 1; } return 0; } - + int compaq_nvram_store (void __iomem *rom_start) { int rc = 1; diff --git a/drivers/pci/hotplug/cpqphp_nvram.h b/drivers/pci/hotplug/cpqphp_nvram.h index e89c0702119..34e4e54fcf1 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.h +++ b/drivers/pci/hotplug/cpqphp_nvram.h @@ -30,26 +30,26 @@ #ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM -static inline void compaq_nvram_init (void __iomem *rom_start) +static inline void compaq_nvram_init(void __iomem *rom_start) { return; } -static inline int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) +static inline int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl) { return 0; } -static inline int compaq_nvram_store (void __iomem *rom_start) +static inline int compaq_nvram_store(void __iomem *rom_start) { return 0; } #else -extern void compaq_nvram_init (void __iomem *rom_start); -extern int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl); -extern int compaq_nvram_store (void __iomem *rom_start); +void compaq_nvram_init(void __iomem *rom_start); +int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl); +int compaq_nvram_store(void __iomem *rom_start); #endif diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 93e39c4096a..1c8c2f130d3 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -26,7 +26,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> @@ -34,10 +33,10 @@ #include <linux/workqueue.h> #include <linux/proc_fs.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ u8 cpqhp_nic_irq; @@ -82,14 +81,15 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom } -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +int cpqhp_configure_device (struct controller *ctrl, struct pci_func *func) { - unsigned char bus; struct pci_bus *child; int num; + pci_lock_rescan_remove(); + if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); /* No pci device, we need to create it then */ if (func->pci_dev == NULL) { @@ -99,34 +99,43 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) if (num) pci_bus_add_devices(ctrl->pci_dev->bus); - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); if (func->pci_dev == NULL) { dbg("ERROR: pci_dev still null\n"); - return 0; + goto out; } } if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); + pci_hp_add_bridge(func->pci_dev); + child = func->pci_dev->subordinate; + if (child) + pci_bus_add_devices(child); } + pci_dev_put(func->pci_dev); + + out: + pci_unlock_rescan_remove(); return 0; } -int cpqhp_unconfigure_device(struct pci_func* func) +int cpqhp_unconfigure_device(struct pci_func *func) { int j; - - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); + + pci_lock_rescan_remove(); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, PCI_DEVFN(func->device, j)); - if (temp) - pci_remove_bus_device(temp); + struct pci_dev *temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); + if (temp) { + pci_dev_put(temp); + pci_stop_and_remove_bus_device(temp); + } } + pci_unlock_rescan_remove(); return 0; } @@ -170,41 +179,31 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) fakedev->bus = fakebus; fakebus->number = bus_num; dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(fakedev, int_pin - 0x0a, irq_num); + __func__, dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num); kfree(fakedev); kfree(fakebus); - dbg("%s: rc %d\n", __FUNCTION__, rc); + dbg("%s: rc %d\n", __func__, rc); if (!rc) return !rc; - // set the Edge Level Control Register (ELCR) + /* set the Edge Level Control Register (ELCR) */ temp_word = inb(0x4d0); temp_word |= inb(0x4d1) << 8; temp_word |= 0x01 << irq_num; - // This should only be for x86 as it sets the Edge Level Control Register - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); - rc = 0; - } + /* This should only be for x86 as it sets the Edge Level + * Control Register + */ + outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word & + 0xFF00) >> 8), 0x4d1); rc = 0; } return rc; } -/* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the - * compiler happy. - */ -static int PCI_ScanBusNonBridge (u8 bus, u8 device) -{ - return 0; -} - -static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_num) { u16 tdevice; u32 work; @@ -213,11 +212,11 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev ctrl->pci_bus->number = bus_num; for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. Not a bridge ? + /* Yep we got one. Not a bridge ? */ if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { *dev_num = tdevice; dbg("found it !\n"); @@ -225,16 +224,16 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev } } for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. bridge ? + /* Yep we got one. bridge ? */ if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); + /* XXX: no recursion, wtf? */ dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) - return 0; + return 0; } } @@ -244,41 +243,23 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) { - struct irq_routing_table *PCIIRQRoutingInfoLength; - long len; - long loop; + int loop, len; u32 work; - u8 tbus, tdevice, tslot; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; if (tslot == slot) { *bus_num = tbus; *dev_num = tdevice; ctrl->pci_bus->number = tbus; pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); - if (!nobridge || (work == 0xffffffff)) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + if (!nobridge || (work == 0xffffffff)) return 0; - } dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); @@ -289,31 +270,26 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num dbg("Scan bus for Non Bridge: bus %d\n", tbus); if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { *bus_num = tbus; - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); return 0; } - } else { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + } else return 0; - } - } } - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); return -1; } -int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot) { - return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) + /* plain (bridges allowed) */ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); } -/* More PCI configuration routines; this time centered around hotplug controller */ +/* More PCI configuration routines; this time centered around hotplug + * controller + */ /* @@ -321,7 +297,7 @@ int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 s * * Reads configuration for all slots in a PCI bus and saves info. * - * Note: For non-hot plug busses, the slot # saved is the device # + * Note: For non-hot plug buses, the slot # saved is the device # * * returns 0 if success */ @@ -344,12 +320,12 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) int stop_it; int index; - // Decide which slots are supported + /* Decide which slots are supported */ if (is_hot_plug) { - //********************************* - // is_hot_plug is the slot mask - //********************************* + /* + * is_hot_plug is the slot mask + */ FirstSupported = is_hot_plug >> 4; LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; } else { @@ -357,123 +333,127 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) LastSupported = 0x1F; } - // Save PCI configuration space for all devices in supported slots + /* Save PCI configuration space for all devices in supported slots */ ctrl->pci_bus->number = busnumber; for (device = FirstSupported; device <= LastSupported; device++) { ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { + if (is_hot_plug) { + /* Setup slot structure with entry for empty + * slot + */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; - if (ID != 0xFFFFFFFF) { // device in slot - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); - if (rc) - return rc; + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + continue; + } - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; - // If multi-function device, set max_functions to 8 - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; - function = 0; + /* If multi-function device, set max_functions to 8 */ + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; - do { - DevError = 0; + function = 0; - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge - // Recurse the subordinate bus - // get the subordinate bus number - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { + do { + DevError = 0; + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus + * get the subordinate bus number + */ + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + /* Save secondary bus cfg spc + * with this recursive call. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) return rc; - } else { - sub_bus = (int) secondary_bus; - - // Save secondary bus cfg spc - // with this recursive call. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return rc; - ctrl->pci_bus->number = busnumber; - } + ctrl->pci_bus->number = busnumber; } + } - index = 0; + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && - (new_slot->function != (u8) function)) - new_slot = cpqhp_slot_find(busnumber, device, index++); - - if (!new_slot) { - // Setup slot structure. - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) - return(1); - } - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - // In case of unsupported board - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - if (rc) - return rc; - } + if (!new_slot) { + /* Setup slot structure. */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; + } - function++; + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + /* In case of unsupported board */ + new_slot->status = DevError; + new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); - stop_it = 0; + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } - // this loop skips to the next present function - // reading in Class Code and Header type. + pci_dev_put(new_slot->pci_dev); - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); - if (rc) - return rc; + function++; - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; + stop_it = 0; - stop_it++; - } + /* this loop skips to the next present function + * reading in Class Code and Header type. + */ + while ((function < max_functions) && (!stop_it)) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { + function++; + continue; } + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; - } while (function < max_functions); - } // End of IF (device in slot?) - else if (is_hot_plug) { - // Setup slot structure with entry for empty slot - new_slot = cpqhp_slot_create(busnumber); + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; - if (new_slot == NULL) { - return(1); + stop_it++; } - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } // End of FOR loop + } while (function < max_functions); + } /* End of FOR loop */ - return(0); + return 0; } @@ -481,11 +461,11 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) * cpqhp_save_slot_config * * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. + * including subordinate buses. * * returns 0 if success */ -int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func *new_slot) { long rc; u8 class_code; @@ -494,7 +474,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) u8 secondary_bus; int sub_bus; int max_functions; - int function; + int function = 0; int cloop = 0; int stop_it; @@ -503,63 +483,58 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) ctrl->pci_bus->number = new_slot->bus; pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { // device in slot - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Recurse the subordinate bus - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (ID == 0xFFFFFFFF) + return 2; - sub_bus = (int) secondary_bus; + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - // Save the config headers for the secondary bus. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return(rc); - ctrl->pci_bus->number = new_slot->bus; + if (header_type & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; - } // End of IF + while (function < max_functions) { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus */ + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); - new_slot->status = 0; + sub_bus = (int) secondary_bus; - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - } + /* Save the config headers for the secondary + * bus. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return(rc); + ctrl->pci_bus->number = new_slot->bus; - function++; + } - stop_it = 0; + new_slot->status = 0; - // this loop skips to the next present function - // reading in the Class Code and the Header type. + for (cloop = 0; cloop < 0x20; cloop++) + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + function++; - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + stop_it = 0; - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - stop_it++; - } + if (ID == 0xFFFFFFFF) + function++; + else { + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + stop_it++; } + } - } while (function < max_functions); - } // End of IF (device in slot?) - else { - return 2; } return 0; @@ -574,7 +549,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) * * returns 0 if success */ -int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -595,11 +570,10 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - // PCI-PCI Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -615,23 +589,27 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) } pci_bus->number = func->bus; - //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together - // Figure out IO and memory base lengths + /* FIXME: this loop is duplicated in the non-bridge + * case. The two could be rolled together Figure out + * IO and memory base lengths + */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -642,32 +620,36 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - - } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge - // Figure out IO and memory base lengths + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // base = amount of IO space requested + /* IO base + * base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base - // base = amount of memory space requested + /* memory base + * base = amount of memory + * space requested + */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -678,16 +660,16 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - } else { // Some other unknown header type + } else { /* Some other unknown header type */ } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -704,7 +686,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) * * returns 0 if success */ -int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -733,18 +715,18 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Save the command register + /* Save the command register */ pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); - // disable card + /* disable card */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Clear Bridge Control Register + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Clear Bridge Control Register */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); @@ -760,7 +742,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) bus_node->next = func->bus_head; func->bus_head = bus_node; - // Save IO base and Limit registers + /* Save IO base and Limit registers */ pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base); pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length); @@ -776,7 +758,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->io_head = io_node; } - // Save memory base and Limit registers + /* Save memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); @@ -792,7 +774,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->mem_head = mem_node; } - // Save prefetchable memory base and Limit registers + /* Save prefetchable memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); @@ -807,7 +789,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); @@ -817,11 +799,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -839,7 +824,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -856,7 +841,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -873,9 +858,10 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else if ((header_type & 0x7F) == 0x00) { // Standard header - // Figure out IO and memory base lengths + } /* End of base register loop */ + /* Standard header */ + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); @@ -885,11 +871,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -906,7 +895,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -923,7 +912,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -940,15 +929,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else { // Some other unknown header type + } /* End of base register loop */ } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } - return(0); + return 0; } @@ -961,7 +949,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) * * returns 0 if success */ -int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func) { int cloop; u8 header_type; @@ -980,16 +968,16 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Start at the top of config space so that the control - // registers are programmed last - for (cloop = 0x3C; cloop > 0; cloop -= 4) { + /* Start at the top of config space so that the control + * registers are programmed last + */ + for (cloop = 0x3C; cloop > 0; cloop -= 4) pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); - } pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - // If this is a bridge device, restore subordinate devices - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + /* If this is a bridge device, restore subordinate devices */ + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -1005,8 +993,9 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) } } else { - // Check all the base Address Registers to make sure - // they are the same. If not, the board is different. + /* Check all the base Address Registers to make sure + * they are the same. If not, the board is different. + */ for (cloop = 16; cloop < 40; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); @@ -1038,7 +1027,7 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) * * returns 0 if the board is the same nonzero otherwise */ -int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -1063,27 +1052,28 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); - // No adapter present + /* No adapter present */ if (temp_register == 0xFFFFFFFF) return(NO_ADAPTER_PRESENT); if (temp_register != func->config_space[0]) return(ADAPTER_NOT_SAME); - // Check for same revision number and class code + /* Check for same revision number and class code */ pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); - // Adapter not the same + /* Adapter not the same */ if (temp_register != func->config_space[0x08 >> 2]) return(ADAPTER_NOT_SAME); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // In order to continue checking, we must program the - // bus registers in the bridge to respond to accesses - // for it's subordinate bus(es) + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* In order to continue checking, we must program the + * bus registers in the bridge to respond to accesses + * for its subordinate bus(es) + */ temp_register = func->config_space[0x18 >> 2]; pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); @@ -1101,35 +1091,39 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) } } - // Check to see if it is a standard config header + /* Check to see if it is a standard config header */ else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Check subsystem vendor and ID + /* Check subsystem vendor and ID */ pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); if (temp_register != func->config_space[0x2C >> 2]) { - // If it's a SMART-2 and the register isn't filled - // in, ignore the difference because - // they just have an old rev of the firmware - + /* If it's a SMART-2 and the register isn't + * filled in, ignore the difference because + * they just have an old rev of the firmware + */ if (!((func->config_space[0] == 0xAE100E11) && (temp_register == 0x00L))) return(ADAPTER_NOT_SAME); } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO + * space requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -1140,23 +1134,24 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) type = 0; } - // Check information in slot structure + /* Check information in slot structure */ if (func->base_length[(cloop - 0x10) >> 2] != base) return(ADAPTER_NOT_SAME); if (func->base_type[(cloop - 0x10) >> 2] != type) return(ADAPTER_NOT_SAME); - } // End of base register loop + } /* End of base register loop */ - } // End of (type 0 config space) else + } /* End of (type 0 config space) else */ else { - // this is not a type 0 or 1 config space header so - // we don't know how to do it + /* this is not a type 0 or 1 config space header so + * we don't know how to do it + */ return(DEVICE_TYPE_NOT_SUPPORTED); } - // Get the next function + /* Get the next function */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -1173,7 +1168,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) * this function is for hot plug ADD! * * returns 0 if success - */ + */ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start) { u8 temp; @@ -1192,10 +1187,10 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); dbg("rom_resource_table = %p\n", rom_resource_table); - if (rom_resource_table == NULL) { + if (rom_resource_table == NULL) return -ENODEV; - } - // Sum all resources and setup resource maps + + /* Sum all resources and setup resource maps */ unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); dbg("unused_IRQ = %x\n", unused_IRQ); @@ -1227,13 +1222,11 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st temp = 0; - if (!cpqhp_nic_irq) { + if (!cpqhp_nic_irq) cpqhp_nic_irq = ctrl->cfgspc_irq; - } - if (!cpqhp_disk_irq) { + if (!cpqhp_disk_irq) cpqhp_disk_irq = ctrl->cfgspc_irq; - } dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); @@ -1267,13 +1260,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, primary_bus, secondary_bus, max_bus); - // If this entry isn't for our controller's bus, ignore it + /* If this entry isn't for our controller's bus, ignore it */ if (primary_bus != ctrl->bus) { i--; one_slot += sizeof (struct slot_rt); continue; } - // find out if this entry is for an occupied slot + /* find out if this entry is for an occupied slot */ ctrl->pci_bus->number = primary_bus; pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); dbg("temp_D_word = %x\n", temp_dword); @@ -1287,13 +1280,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); } - // If we can't find a match, skip this table entry + /* If we can't find a match, skip this table entry */ if (!func) { i--; one_slot += sizeof (struct slot_rt); continue; } - // this may not work and shouldn't be used + /* this may not work and shouldn't be used */ if (secondary_bus != primary_bus) bridged_slot = 1; else @@ -1306,7 +1299,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } - // If we've got a valid IO base, use it + /* If we've got a valid IO base, use it */ temp_dword = io_base + io_length; @@ -1330,7 +1323,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid memory base, use it + /* If we've got a valid memory base, use it */ temp_dword = mem_base + mem_length; if ((mem_base) && (temp_dword < 0x10000)) { mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); @@ -1353,8 +1346,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid prefetchable memory base, and - // the base + length isn't greater than 0xFFFF + /* If we've got a valid prefetchable memory base, and + * the base + length isn't greater than 0xFFFF + */ temp_dword = pre_mem_base + pre_mem_length; if ((pre_mem_base) && (temp_dword < 0x10000)) { p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); @@ -1377,9 +1371,10 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid bus number, use it - // The second condition is to ignore bus numbers on - // populated slots that don't have PCI-PCI bridges + /* If we've got a valid bus number, use it + * The second condition is to ignore bus numbers on + * populated slots that don't have PCI-PCI bridges + */ if (secondary_bus && (secondary_bus != primary_bus)) { bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); if (!bus_node) @@ -1403,8 +1398,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st one_slot += sizeof (struct slot_rt); } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); @@ -1423,12 +1419,12 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st * * returns 0 if success */ -int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +int cpqhp_return_board_resources(struct pci_func *func, struct resource_lists *resources) { int rc = 0; struct pci_resource *node; struct pci_resource *t_node; - dbg("%s\n", __FUNCTION__); + dbg("%s\n", __func__); if (!func) return 1; @@ -1479,7 +1475,7 @@ int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * * * Puts node back in the resource list pointed to by head */ -void cpqhp_destroy_resource_list (struct resource_lists * resources) +void cpqhp_destroy_resource_list (struct resource_lists *resources) { struct pci_resource *res, *tres; @@ -1526,7 +1522,7 @@ void cpqhp_destroy_resource_list (struct resource_lists * resources) * * Puts node back in the resource list pointed to by head */ -void cpqhp_destroy_board_resources (struct pci_func * func) +void cpqhp_destroy_board_resources (struct pci_func *func) { struct pci_resource *res, *tres; @@ -1566,4 +1562,3 @@ void cpqhp_destroy_board_resources (struct pci_func * func) kfree(tres); } } - diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 4c11048ad51..4a392c44e3d 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -26,29 +26,25 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/workqueue.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> #include "cpqphp.h" - -/* A few routines that create sysfs entries for the hot plug controller */ - -static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) +static DEFINE_MUTEX(cpqphp_mutex); +static int show_ctrl (struct controller *ctrl, char *buf) { - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; + char *out = buf; int index; struct pci_resource *res; - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - out += sprintf(buf, "Free resources: memory\n"); index = 11; res = ctrl->mem_head; @@ -80,22 +76,16 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha return out - buf; } -static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) +static int show_dev (struct controller *ctrl, char *buf) { - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; + char *out = buf; int index; struct pci_resource *res; struct pci_func *new_slot; struct slot *slot; - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - slot=ctrl->slot; + slot = ctrl->slot; while (slot) { new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); @@ -134,10 +124,100 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char return out - buf; } -static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); -void cpqhp_create_ctrl_files (struct controller *ctrl) +static int spew_debug_info(struct controller *ctrl, char *data, int size) +{ + int used; + + used = size - show_ctrl(ctrl, data); + used = (size - used) - show_dev(ctrl, &data[used]); + return used; +} + +struct ctrl_dbg { + int size; + char *data; + struct controller *ctrl; +}; + +#define MAX_OUTPUT (4*PAGE_SIZE) + +static int open(struct inode *inode, struct file *file) +{ + struct controller *ctrl = inode->i_private; + struct ctrl_dbg *dbg; + int retval = -ENOMEM; + + mutex_lock(&cpqphp_mutex); + dbg = kmalloc(sizeof(*dbg), GFP_KERNEL); + if (!dbg) + goto exit; + dbg->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); + if (!dbg->data) { + kfree(dbg); + goto exit; + } + dbg->size = spew_debug_info(ctrl, dbg->data, MAX_OUTPUT); + file->private_data = dbg; + retval = 0; +exit: + mutex_unlock(&cpqphp_mutex); + return retval; +} + +static loff_t lseek(struct file *file, loff_t off, int whence) +{ + struct ctrl_dbg *dbg = file->private_data; + return fixed_size_llseek(file, off, whence, dbg->size); +} + +static ssize_t read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct ctrl_dbg *dbg = file->private_data; + return simple_read_from_buffer(buf, nbytes, ppos, dbg->data, dbg->size); +} + +static int release(struct inode *inode, struct file *file) +{ + struct ctrl_dbg *dbg = file->private_data; + + kfree(dbg->data); + kfree(dbg); + return 0; +} + +static const struct file_operations debug_ops = { + .owner = THIS_MODULE, + .open = open, + .llseek = lseek, + .read = read, + .release = release, +}; + +static struct dentry *root; + +void cpqhp_initialize_debugfs(void) +{ + if (!root) + root = debugfs_create_dir("cpqhp", NULL); +} + +void cpqhp_shutdown_debugfs(void) +{ + debugfs_remove(root); +} + +void cpqhp_create_debugfs_files(struct controller *ctrl) { - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); - device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); + ctrl->dentry = debugfs_create_file(dev_name(&ctrl->pci_dev->dev), + S_IRUGO, root, ctrl, &debug_ops); } + +void cpqhp_remove_debugfs_files(struct controller *ctrl) +{ + if (ctrl->dentry) + debugfs_remove(ctrl->dentry); + ctrl->dentry = NULL; +} + diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c deleted file mode 100644 index 060d74775d7..00000000000 --- a/drivers/pci/hotplug/fakephp.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Fake PCI Hot Plug Controller Driver - * - * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (C) 2003 IBM Corp. - * Copyright (C) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de> - * - * Based on ideas and code from: - * Vladimir Kondratiev <vladimir.kondratiev@intel.com> - * Rolf Eike Beer <eike-kernel@sf-tec.de> - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * Send feedback to <greg@kroah.com> - */ - -/* - * - * This driver will "emulate" removing PCI devices from the system. If - * the "power" file is written to with "0" then the specified PCI device - * will be completely removed from the kernel. - * - * WARNING, this does NOT turn off the power to the PCI device. This is - * a "logical" removal, not a physical or electrical removal. - * - * Use this module at your own risk, you have been warned! - * - * Enabling PCI devices is left as an exercise for the reader... - * - */ -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/slab.h> -#include "pci_hotplug.h" -#include "../pci.h" - -#if !defined(MODULE) - #define MY_NAME "fakephp" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## 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 DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" -#define DRIVER_DESC "Fake PCI Hot Plug Controller Driver" - -struct dummy_slot { - struct list_head node; - struct hotplug_slot *slot; - struct pci_dev *dev; -}; - -static int debug; -static LIST_HEAD(slot_list); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); - -static struct hotplug_slot_ops dummy_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, -}; - -static void dummy_release(struct hotplug_slot *slot) -{ - struct dummy_slot *dslot = slot->private; - - list_del(&dslot->node); - kfree(dslot->slot->info); - kfree(dslot->slot); - pci_dev_put(dslot->dev); - kfree(dslot); -} - -static int add_slot(struct pci_dev *dev) -{ - struct dummy_slot *dslot; - struct hotplug_slot *slot; - int retval = -ENOMEM; - - slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot) - goto error; - memset(slot, 0, sizeof(*slot)); - - slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->info) - goto error_slot; - memset(slot->info, 0, sizeof(struct hotplug_slot_info)); - - slot->info->power_status = 1; - slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; - slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; - - slot->name = &dev->dev.bus_id[0]; - dbg("slot->name = %s\n", slot->name); - - dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); - if (!dslot) - goto error_info; - - slot->ops = &dummy_hotplug_slot_ops; - slot->release = &dummy_release; - slot->private = dslot; - - retval = pci_hp_register(slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - goto error_dslot; - } - - dslot->slot = slot; - dslot->dev = pci_dev_get(dev); - list_add (&dslot->node, &slot_list); - return retval; - -error_dslot: - kfree(dslot); -error_info: - kfree(slot->info); -error_slot: - kfree(slot); -error: - return retval; -} - -static int __init pci_scan_buses(void) -{ - struct pci_dev *dev = NULL; - int retval = 0; - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - retval = add_slot(dev); - if (retval) { - pci_dev_put(dev); - break; - } - } - - return retval; -} - -static void remove_slot(struct dummy_slot *dslot) -{ - int retval; - - dbg("removing slot %s\n", dslot->slot->name); - retval = pci_hp_deregister(dslot->slot); - if (retval) - err("Problem unregistering a slot %s\n", dslot->slot->name); -} - -/** - * Rescan slot. - * Tries hard not to re-enable already existing devices - * also handles scanning of subfunctions - * - * @param temp Device template. Should be set: bus and devfn. - */ -static void pci_rescan_slot(struct pci_dev *temp) -{ - struct pci_bus *bus = temp->bus; - struct pci_dev *dev; - int func; - u8 hdr_type; - if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { - temp->hdr_type = hdr_type & 0x7f; - if (!pci_find_slot(bus->number, temp->devfn)) { - dev = pci_scan_single_device(bus, temp->devfn); - if (dev) { - dbg("New device on %s function %x:%x\n", - bus->name, temp->devfn >> 3, - temp->devfn & 7); - pci_bus_add_device(dev); - add_slot(dev); - } - } - /* multifunction device? */ - if (!(hdr_type & 0x80)) - return; - - /* continue scanning for other functions */ - for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) { - if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) - continue; - temp->hdr_type = hdr_type & 0x7f; - - if (!pci_find_slot(bus->number, temp->devfn)) { - dev = pci_scan_single_device(bus, temp->devfn); - if (dev) { - dbg("New device on %s function %x:%x\n", - bus->name, temp->devfn >> 3, - temp->devfn & 7); - pci_bus_add_device(dev); - add_slot(dev); - } - } - } - } -} - - -/** - * Rescan PCI bus. - * call pci_rescan_slot for each possible function of the bus - * - * @param bus - */ -static void pci_rescan_bus(const struct pci_bus *bus) -{ - unsigned int devfn; - struct pci_dev *dev; - dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); - if (!dev) - return; - - memset(dev, 0, sizeof(dev)); - dev->bus = (struct pci_bus*)bus; - dev->sysdata = bus->sysdata; - for (devfn = 0; devfn < 0x100; devfn += 8) { - dev->devfn = devfn; - pci_rescan_slot(dev); - } - kfree(dev); -} - -/* recursively scan all buses */ -static void pci_rescan_buses(const struct list_head *list) -{ - const struct list_head *l; - list_for_each(l,list) { - const struct pci_bus *b = pci_bus_b(l); - pci_rescan_bus(b); - pci_rescan_buses(&b->children); - } -} - -/* initiate rescan of all pci buses */ -static inline void pci_rescan(void) { - pci_rescan_buses(&pci_root_buses); -} - - -static int enable_slot(struct hotplug_slot *hotplug_slot) -{ - /* mis-use enable_slot for rescanning of the pci bus */ - pci_rescan(); - return -ENODEV; -} - -/* find the hotplug_slot for the pci_dev */ -static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev) -{ - struct dummy_slot *dslot; - - list_for_each_entry(dslot, &slot_list, node) { - if (dslot->dev == dev) - return dslot->slot; - } - return NULL; -} - - -static int disable_slot(struct hotplug_slot *slot) -{ - struct dummy_slot *dslot; - struct hotplug_slot *hslot; - struct pci_dev *dev; - int func; - - if (!slot) - return -ENODEV; - dslot = slot->private; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, slot->name); - - /* don't disable bridged devices just yet, we can't handle them easily... */ - if (dslot->dev->subordinate) { - err("Can't remove PCI devices with other PCI devices behind it yet.\n"); - return -ENODEV; - } - /* search for subfunctions and disable them first */ - if (!(dslot->dev->devfn & 7)) { - for (func = 1; func < 8; func++) { - dev = pci_find_slot(dslot->dev->bus->number, - dslot->dev->devfn + func); - if (dev) { - hslot = get_slot_from_dev(dev); - if (hslot) - disable_slot(hslot); - else { - err("Hotplug slot not found for subfunction of PCI device\n"); - return -ENODEV; - } - } else - dbg("No device in slot found\n"); - } - } - - /* remove the device from the pci core */ - pci_remove_bus_device(dslot->dev); - - /* blow away this sysfs entry and other parts. */ - remove_slot(dslot); - - return 0; -} - -static void cleanup_slots (void) -{ - struct list_head *tmp; - struct list_head *next; - struct dummy_slot *dslot; - - list_for_each_safe (tmp, next, &slot_list) { - dslot = list_entry (tmp, struct dummy_slot, node); - remove_slot(dslot); - } - -} - -static int __init dummyphp_init(void) -{ - info(DRIVER_DESC "\n"); - - return pci_scan_buses(); -} - - -static void __exit dummyphp_exit(void) -{ - cleanup_slots(); -} - -module_init(dummyphp_init); -module_exit(dummyphp_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index c22e0284d7b..e3e46a7b3ee 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -30,7 +30,7 @@ * */ -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> extern int ibmphp_debug; @@ -59,7 +59,7 @@ extern int ibmphp_debug; /************************************************************ -* RESOURE TYPE * +* RESOURCE TYPE * ************************************************************/ #define EBDA_RSRC_TYPE_MASK 0x03 @@ -103,7 +103,7 @@ extern int ibmphp_debug; //-------------------------------------------------------------- struct rio_table_hdr { - u8 ver_num; + u8 ver_num; u8 scal_count; u8 riodev_count; u16 offset; @@ -127,7 +127,7 @@ struct scal_detail { }; //-------------------------------------------------------------- -// RIO DETAIL +// RIO DETAIL //-------------------------------------------------------------- struct rio_detail { @@ -152,7 +152,7 @@ struct opt_rio { u8 first_slot_num; u8 middle_num; struct list_head opt_rio_list; -}; +}; struct opt_rio_lo { u8 rio_type; @@ -161,7 +161,7 @@ struct opt_rio_lo { u8 middle_num; u8 pack_count; struct list_head opt_rio_lo_list; -}; +}; /**************************************************************** * HPC DESCRIPTOR NODE * @@ -275,17 +275,17 @@ extern struct list_head ibmphp_slot_head; * FUNCTION PROTOTYPES * ***********************************************************/ -extern void ibmphp_free_ebda_hpc_queue (void); -extern int ibmphp_access_ebda (void); -extern struct slot *ibmphp_get_slot_from_physical_num (u8); -extern int ibmphp_get_total_hp_slots (void); -extern void ibmphp_free_ibm_slot (struct slot *); -extern void ibmphp_free_bus_info_queue (void); -extern void ibmphp_free_ebda_pci_rsrc_queue (void); -extern struct bus_info *ibmphp_find_same_bus_num (u32); -extern int ibmphp_get_bus_index (u8); -extern u16 ibmphp_get_total_controllers (void); -extern int ibmphp_register_pci (void); +void ibmphp_free_ebda_hpc_queue(void); +int ibmphp_access_ebda(void); +struct slot *ibmphp_get_slot_from_physical_num(u8); +int ibmphp_get_total_hp_slots(void); +void ibmphp_free_ibm_slot(struct slot *); +void ibmphp_free_bus_info_queue(void); +void ibmphp_free_ebda_pci_rsrc_queue(void); +struct bus_info *ibmphp_find_same_bus_num(u32); +int ibmphp_get_bus_index(u8); +u16 ibmphp_get_total_controllers(void); +int ibmphp_register_pci(void); /* passed parameters */ #define MEM 0 @@ -381,24 +381,24 @@ struct res_needed { /* functions */ -extern int ibmphp_rsrc_init (void); -extern int ibmphp_add_resource (struct resource_node *); -extern int ibmphp_remove_resource (struct resource_node *); -extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); -extern int ibmphp_check_resource (struct resource_node *, u8); -extern int ibmphp_remove_bus (struct bus_node *, u8); -extern void ibmphp_free_resources (void); -extern int ibmphp_add_pfmem_from_mem (struct resource_node *); -extern struct bus_node *ibmphp_find_res_bus (u8); -extern void ibmphp_print_test (void); /* for debugging purposes */ +int ibmphp_rsrc_init(void); +int ibmphp_add_resource(struct resource_node *); +int ibmphp_remove_resource(struct resource_node *); +int ibmphp_find_resource(struct bus_node *, u32, struct resource_node **, int); +int ibmphp_check_resource(struct resource_node *, u8); +int ibmphp_remove_bus(struct bus_node *, u8); +void ibmphp_free_resources(void); +int ibmphp_add_pfmem_from_mem(struct resource_node *); +struct bus_node *ibmphp_find_res_bus(u8); +void ibmphp_print_test(void); /* for debugging purposes */ -extern void ibmphp_hpc_initvars (void); -extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); -extern int ibmphp_hpc_writeslot (struct slot *, u8); -extern void ibmphp_lock_operations (void); -extern void ibmphp_unlock_operations (void); -extern int ibmphp_hpc_start_poll_thread (void); -extern void ibmphp_hpc_stop_poll_thread (void); +void ibmphp_hpc_initvars(void); +int ibmphp_hpc_readslot(struct slot *, u8, u8 *); +int ibmphp_hpc_writeslot(struct slot *, u8); +void ibmphp_lock_operations(void); +void ibmphp_unlock_operations(void); +int ibmphp_hpc_start_poll_thread(void); +void ibmphp_hpc_stop_poll_thread(void); //---------------------------------------------------------------------------- @@ -406,8 +406,6 @@ extern void ibmphp_hpc_stop_poll_thread (void); //---------------------------------------------------------------------------- // HPC return codes //---------------------------------------------------------------------------- -#define FALSE 0x00 -#define TRUE 0x01 #define HPC_ERROR 0xFF //----------------------------------------------------------------------------- @@ -576,7 +574,7 @@ extern void ibmphp_hpc_stop_poll_thread (void); #define HPC_CTLR_IRQ_PENDG 0x80 //---------------------------------------------------------------------------- -// HPC_CTLR_WROKING status return codes +// HPC_CTLR_WORKING status return codes //---------------------------------------------------------------------------- #define HPC_CTLR_WORKING_NO 0x00 #define HPC_CTLR_WORKING_YES 0x01 @@ -709,17 +707,16 @@ struct slot { u8 device; u8 number; u8 real_physical_slot_num; - char name[100]; u32 capabilities; u8 supported_speed; u8 supported_bus_mode; + u8 flag; /* this is for disable slot and polling */ + u8 ctlr_index; struct hotplug_slot *hotplug_slot; struct controller *ctrl; struct pci_func *func; u8 irq[4]; - u8 flag; /* this is for disable slot and polling */ int bit_mode; /* 0 = 32, 1 = 64 */ - u8 ctlr_index; struct bus_info *bus_on; struct list_head ibm_slot_list; u8 status; @@ -752,11 +749,11 @@ struct controller { /* Functions */ -extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ -extern int ibmphp_do_disable_slot (struct slot *slot_cur); -extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ -extern int ibmphp_configure_card (struct pci_func *, u8); -extern int ibmphp_unconfigure_card (struct slot **, int); +int ibmphp_init_devno(struct slot **); /* This function is called from EBDA, so we need it not be static */ +int ibmphp_do_disable_slot(struct slot *slot_cur); +int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be be static */ +int ibmphp_configure_card(struct pci_func *, u8); +int ibmphp_unconfigure_card(struct slot **, int); extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; #endif //__IBMPHP_H diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index aabf1e70b52..f7b8684a773 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -34,9 +34,8 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/wait.h> -#include <linux/smp_lock.h> #include "../pci.h" -#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ +#include <asm/pci_x86.h> /* for struct irq_routing_table */ #include "ibmphp.h" #define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) @@ -50,7 +49,7 @@ int ibmphp_debug; -static int debug; +static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); MODULE_LICENSE ("GPL"); @@ -59,7 +58,7 @@ MODULE_DESCRIPTION (DRIVER_DESC); struct pci_bus *ibmphp_pci_bus; static int max_slots; -static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS +static int irqs[16]; /* PIC mode IRQs we're using so far (in case MPS * tables don't provide default info for empty slots */ static int init_flag; @@ -72,20 +71,20 @@ static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) return get_max_adapter_speed_1 (hs, value, 1); } */ -static inline int get_cur_bus_info(struct slot **sl) +static inline int get_cur_bus_info(struct slot **sl) { int rc = 1; - struct slot * slot_cur = *sl; + struct slot *slot_cur = *sl; debug("options = %x\n", slot_cur->ctrl->options); - debug("revision = %x\n", slot_cur->ctrl->revision); + debug("revision = %x\n", slot_cur->ctrl->revision); - if (READ_BUS_STATUS(slot_cur->ctrl)) + if (READ_BUS_STATUS(slot_cur->ctrl)) rc = ibmphp_hpc_readslot(slot_cur, READ_BUSSTATUS, NULL); - - if (rc) + + if (rc) return rc; - + slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED(slot_cur->busstatus); if (READ_BUS_MODE(slot_cur->ctrl)) slot_cur->bus_on->current_bus_mode = @@ -97,7 +96,7 @@ static inline int get_cur_bus_info(struct slot **sl) slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); - + *sl = slot_cur; return 0; } @@ -105,8 +104,8 @@ static inline int get_cur_bus_info(struct slot **sl) static inline int slot_update(struct slot **sl) { int rc; - rc = ibmphp_hpc_readslot(*sl, READ_ALLSTAT, NULL); - if (rc) + rc = ibmphp_hpc_readslot(*sl, READ_ALLSTAT, NULL); + if (rc) return rc; if (!init_flag) rc = get_cur_bus_info(sl); @@ -115,8 +114,8 @@ static inline int slot_update(struct slot **sl) static int __init get_max_slots (void) { - struct slot * slot_cur; - struct list_head * tmp; + struct slot *slot_cur; + struct list_head *tmp; u8 slot_count = 0; list_for_each(tmp, &ibmphp_slot_head) { @@ -149,50 +148,56 @@ int ibmphp_init_devno(struct slot **cur_slot) len = (rtable->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - if (!len) + if (!len) { + kfree(rtable); return -1; + } for (loop = 0; loop < len; loop++) { - if ((*cur_slot)->number == rtable->slots[loop].slot) { - if ((*cur_slot)->bus == rtable->slots[loop].bus) { + if ((*cur_slot)->number == rtable->slots[loop].slot && + (*cur_slot)->bus == rtable->slots[loop].bus) { + struct io_apic_irq_attr irq_attr; + (*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn); for (i = 0; i < 4; i++) (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus, - (int) (*cur_slot)->device, i); - - debug("(*cur_slot)->irq[0] = %x\n", - (*cur_slot)->irq[0]); - debug("(*cur_slot)->irq[1] = %x\n", - (*cur_slot)->irq[1]); - debug("(*cur_slot)->irq[2] = %x\n", - (*cur_slot)->irq[2]); - debug("(*cur_slot)->irq[3] = %x\n", - (*cur_slot)->irq[3]); - - debug("rtable->exlusive_irqs = %x\n", + (int) (*cur_slot)->device, i, + &irq_attr); + + debug("(*cur_slot)->irq[0] = %x\n", + (*cur_slot)->irq[0]); + debug("(*cur_slot)->irq[1] = %x\n", + (*cur_slot)->irq[1]); + debug("(*cur_slot)->irq[2] = %x\n", + (*cur_slot)->irq[2]); + debug("(*cur_slot)->irq[3] = %x\n", + (*cur_slot)->irq[3]); + + debug("rtable->exclusive_irqs = %x\n", rtable->exclusive_irqs); - debug("rtable->slots[loop].irq[0].bitmap = %x\n", + debug("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); - debug("rtable->slots[loop].irq[1].bitmap = %x\n", + debug("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); - debug("rtable->slots[loop].irq[2].bitmap = %x\n", + debug("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); - debug("rtable->slots[loop].irq[3].bitmap = %x\n", + debug("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); - debug("rtable->slots[loop].irq[0].link = %x\n", + debug("rtable->slots[loop].irq[0].link = %x\n", rtable->slots[loop].irq[0].link); - debug("rtable->slots[loop].irq[1].link = %x\n", + debug("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); - debug("rtable->slots[loop].irq[2].link = %x\n", + debug("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); - debug("rtable->slots[loop].irq[3].link = %x\n", + debug("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); - debug("end of init_devno\n"); - return 0; - } + debug("end of init_devno\n"); + kfree(rtable); + return 0; } } + kfree(rtable); return -1; } @@ -235,12 +240,12 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { int rc = 0; struct slot *pslot; - u8 cmd; + u8 cmd = 0x00; /* avoid compiler warning */ debug("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); ibmphp_lock_operations(); - cmd = 0x00; // avoid compiler warning + if (hotplug_slot) { switch (value) { @@ -266,7 +271,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) else rc = -ENODEV; } - } else + } else rc = -ENODEV; ibmphp_unlock_operations(); @@ -275,7 +280,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) return rc; } -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -283,9 +288,9 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) debug("get_attention_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)); @@ -306,7 +311,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) return rc; } -static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -315,7 +320,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)); @@ -333,7 +338,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) } -static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -342,7 +347,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)); @@ -359,7 +364,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) return rc; } -static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -369,7 +374,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)); @@ -390,94 +395,45 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) return rc; } -static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static int get_max_bus_speed(struct slot *slot) { - int rc = -ENODEV; - struct slot *pslot; + int rc; u8 mode = 0; + enum pci_bus_speed speed; + struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus; - debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); + debug("%s - Entry slot[%p]\n", __func__, slot); ibmphp_lock_operations(); - - if (hotplug_slot && value) { - pslot = hotplug_slot->private; - if (pslot) { - rc = 0; - mode = pslot->supported_bus_mode; - *value = pslot->supported_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value = pslot->supported_speed + 0x01; - break; - default: - /* Note (will need to change): there would be soon 256, 512 also */ - rc = -ENODEV; - } - } - } - + mode = slot->supported_bus_mode; + speed = slot->supported_speed; ibmphp_unlock_operations(); - debug("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); - return rc; -} -static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 mode = 0; - - debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); - - ibmphp_lock_operations(); - - if (hotplug_slot && value) { - pslot = hotplug_slot->private; - if (pslot) { - rc = get_cur_bus_info(&pslot); - if (!rc) { - mode = pslot->bus_on->current_bus_mode; - *value = pslot->bus_on->current_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - else if (mode == BUS_MODE_PCI) - ; - else - *value = PCI_SPEED_UNKNOWN; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value += 0x01; - break; - default: - /* Note of change: there would also be 256, 512 soon */ - rc = -ENODEV; - } - } - } + switch (speed) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + speed += 0x01; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + speed += 0x01; + break; + default: + /* Note (will need to change): there would be soon 256, 512 also */ + rc = -ENODEV; } - ibmphp_unlock_operations(); - debug("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); + if (!rc) + bus->max_bus_speed = speed; + + debug("%s - Exit rc[%d] speed[%x]\n", __func__, rc, speed); return rc; } /* -static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 *value, u8 flag) { int rc = -ENODEV; struct slot *pslot; @@ -515,7 +471,7 @@ static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 * value return rc; } -static int get_bus_name(struct hotplug_slot *hotplug_slot, char * value) +static int get_bus_name(struct hotplug_slot *hotplug_slot, char *value) { int rc = -ENODEV; struct slot *pslot = NULL; @@ -559,14 +515,15 @@ static int __init init_ops(void) debug("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); - if (slot_cur->ctrl->revision == 0xFF) + if (slot_cur->ctrl->revision == 0xFF) if (get_ctrl_revision(slot_cur, &slot_cur->ctrl->revision)) return -1; - if (slot_cur->bus_on->current_speed == 0xFF) - if (get_cur_bus_info(&slot_cur)) + if (slot_cur->bus_on->current_speed == 0xFF) + if (get_cur_bus_info(&slot_cur)) return -1; + get_max_bus_speed(slot_cur); if (slot_cur->ctrl->options == 0xFF) if (get_hpc_options(slot_cur, &slot_cur->ctrl->options)) @@ -582,8 +539,8 @@ static int __init init_ops(void) debug("SLOT_PRESENT = %x\n", SLOT_PRESENT(slot_cur->status)); debug("SLOT_LATCH = %x\n", SLOT_LATCH(slot_cur->status)); - if ((SLOT_PWRGD(slot_cur->status)) && - !(SLOT_PRESENT(slot_cur->status)) && + if ((SLOT_PWRGD(slot_cur->status)) && + !(SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) { debug("BEFORE POWER OFF COMMAND\n"); rc = power_off(slot_cur); @@ -624,13 +581,13 @@ static int validate(struct slot *slot_cur, int opn) switch (opn) { case ENABLE: - if (!(SLOT_PWRGD(slot_cur->status)) && - (SLOT_PRESENT(slot_cur->status)) && + if (!(SLOT_PWRGD(slot_cur->status)) && + (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; break; case DISABLE: - if ((SLOT_PWRGD(slot_cur->status)) && + if ((SLOT_PWRGD(slot_cur->status)) && (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; @@ -650,6 +607,7 @@ static int validate(struct slot *slot_cur, int opn) int ibmphp_update_slot_info(struct slot *slot_cur) { struct hotplug_slot_info *info; + struct pci_bus *bus = slot_cur->hotplug_slot->pci_slot->bus; int rc; u8 bus_speed; u8 mode; @@ -659,7 +617,7 @@ int ibmphp_update_slot_info(struct slot *slot_cur) err("out of system memory\n"); return -ENOMEM; } - + info->power_status = SLOT_PWRGD(slot_cur->status); info->attention_status = SLOT_ATTN(slot_cur->status, slot_cur->ext_status); @@ -680,7 +638,7 @@ int ibmphp_update_slot_info(struct slot *slot_cur) case BUS_SPEED_33: break; case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) + if (mode == BUS_MODE_PCIX) bus_speed += 0x01; else if (mode == BUS_MODE_PCI) ; @@ -695,10 +653,9 @@ int ibmphp_update_slot_info(struct slot *slot_cur) bus_speed = PCI_SPEED_UNKNOWN; } - info->cur_bus_speed = bus_speed; - info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed; - // To do: bus_names - + bus->cur_bus_speed = bus_speed; + // To do: bus_names + rc = pci_hp_change_slot_info(slot_cur->hotplug_slot, info); kfree(info); return rc; @@ -714,7 +671,7 @@ static struct pci_func *ibm_slot_find(u8 busno, u8 device, u8 function) { struct pci_func *func_cur; struct slot *slot_cur; - struct list_head * tmp; + struct list_head *tmp; list_for_each(tmp, &ibmphp_slot_head) { slot_cur = list_entry(tmp, struct slot, ibm_slot_list); if (slot_cur->func) { @@ -739,16 +696,16 @@ static struct pci_func *ibm_slot_find(u8 busno, u8 device, u8 function) static void free_slots(void) { struct slot *slot_cur; - struct list_head * tmp; - struct list_head * next; + struct list_head *tmp; + struct list_head *next; - debug("%s -- enter\n", __FUNCTION__); + debug("%s -- enter\n", __func__); list_for_each_safe(tmp, next, &ibmphp_slot_head) { slot_cur = list_entry(tmp, struct slot, ibm_slot_list); pci_hp_deregister(slot_cur->hotplug_slot); } - debug("%s -- exit\n", __FUNCTION__); + debug("%s -- exit\n", __func__); } static void ibm_unconfigure_device(struct pci_func *func) @@ -756,21 +713,29 @@ static void ibm_unconfigure_device(struct pci_func *func) struct pci_dev *temp; u8 j; - debug("inside %s\n", __FUNCTION__); + debug("inside %s\n", __func__); debug("func->device = %x, func->function = %x\n", func->device, func->function); debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); + pci_lock_rescan_remove(); + for (j = 0; j < 0x08; j++) { - temp = pci_find_slot(func->busno, (func->device << 3) | j); - if (temp) - pci_remove_bus_device(temp); + temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); + if (temp) { + pci_stop_and_remove_bus_device(temp); + pci_dev_put(temp); + } } + + pci_dev_put(func->dev); + + pci_unlock_rescan_remove(); } /* - * The following function is to fix kernel bug regarding - * getting bus entries, here we manually add those primary + * The following function is to fix kernel bug regarding + * getting bus entries, here we manually add those primary * bus entries to kernel bus structure whenever apply */ static u8 bus_structure_fixup(u8 busno) @@ -784,13 +749,13 @@ static u8 bus_structure_fixup(u8 busno) bus = kmalloc(sizeof(*bus), GFP_KERNEL); if (!bus) { - err("%s - out of memory\n", __FUNCTION__); + err("%s - out of memory\n", __func__); return 1; } dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { kfree(bus); - err("%s - out of memory\n", __FUNCTION__); + err("%s - out of memory\n", __func__); return 1; } @@ -800,8 +765,8 @@ static u8 bus_structure_fixup(u8 busno) for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) { if (!pci_read_config_word(dev, PCI_VENDOR_ID, &l) && (l != 0x0000) && (l != 0xffff)) { - debug("%s - Inside bus_struture_fixup()\n", - __FUNCTION__); + debug("%s - Inside bus_structure_fixup()\n", + __func__); pci_scan_bus(busno, ibmphp_pci_bus->ops, NULL); break; } @@ -815,51 +780,55 @@ static u8 bus_structure_fixup(u8 busno) static int ibm_configure_device(struct pci_func *func) { - unsigned char bus; struct pci_bus *child; int num; int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ + pci_lock_rescan_remove(); + if (!(bus_structure_fixup(func->busno))) flag = 1; if (func->dev == NULL) - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { struct pci_bus *bus = pci_find_bus(0, func->busno); if (!bus) - return 0; + goto out; num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); if (num) pci_bus_add_devices(bus); - func->dev = pci_find_slot(func->busno, + func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { err("ERROR... : pci_dev still NULL\n"); - return 0; + goto out; } } if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - pci_read_config_byte(func->dev, PCI_SECONDARY_BUS, &bus); - child = pci_add_new_bus(func->dev->bus, func->dev, bus); - pci_do_scan_bus(child); + pci_hp_add_bridge(func->dev); + child = func->dev->subordinate; + if (child) + pci_bus_add_devices(child); } + out: + pci_unlock_rescan_remove(); return 0; } /******************************************************* - * Returns whether the bus is empty or not + * Returns whether the bus is empty or not *******************************************************/ -static int is_bus_empty(struct slot * slot_cur) +static int is_bus_empty(struct slot *slot_cur) { int rc; - struct slot * tmp_slot; + struct slot *tmp_slot; u8 i = slot_cur->bus_on->slot_min; while (i <= slot_cur->bus_on->slot_max) { @@ -882,12 +851,12 @@ static int is_bus_empty(struct slot * slot_cur) } /*********************************************************** - * If the HPC permits and the bus currently empty, tries to set the + * If the HPC permits and the bus currently empty, tries to set the * bus speed and mode at the maximum card and bus capability * Parameters: slot * Returns: bus is set (0) or error code ***********************************************************/ -static int set_bus(struct slot * slot_cur) +static int set_bus(struct slot *slot_cur) { int rc; u8 speed; @@ -896,9 +865,9 @@ static int set_bus(struct slot * slot_cur) static struct pci_device_id ciobx[] = { { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, 0x0101) }, { }, - }; + }; - debug("%s - entry slot # %d\n", __FUNCTION__, slot_cur->number); + debug("%s - entry slot # %d\n", __func__, slot_cur->number); if (SET_BUS_STATUS(slot_cur->ctrl) && is_bus_empty(slot_cur)) { rc = slot_update(&slot_cur); if (rc) @@ -917,7 +886,7 @@ static int set_bus(struct slot * slot_cur) else if (!SLOT_BUS_MODE(slot_cur->ext_status)) /* if max slot/bus capability is 66 pci and there's no bus mode mismatch, then - the adapter supports 66 pci */ + the adapter supports 66 pci */ cmd = HPC_BUS_66CONVMODE; else cmd = HPC_BUS_33CONVMODE; @@ -970,24 +939,24 @@ static int set_bus(struct slot * slot_cur) return -EIO; } } - /* This is for x440, once Brandon fixes the firmware, + /* This is for x440, once Brandon fixes the firmware, will not need this delay */ msleep(1000); - debug("%s -Exit\n", __FUNCTION__); + debug("%s -Exit\n", __func__); return 0; } /* This routine checks the bus limitations that the slot is on from the BIOS. - * This is used in deciding whether or not to power up the slot. + * This is used in deciding whether or not to power up the slot. * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on - * same bus) + * same bus) * Parameters: slot * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus */ static int check_limitations(struct slot *slot_cur) { u8 i; - struct slot * tmp_slot; + struct slot *tmp_slot; u8 count = 0; u8 limitation = 0; @@ -1026,7 +995,7 @@ static int check_limitations(struct slot *slot_cur) static inline void print_card_capability(struct slot *slot_cur) { info("capability of the card is "); - if ((slot_cur->ext_status & CARD_INFO) == PCIX133) + if ((slot_cur->ext_status & CARD_INFO) == PCIX133) info(" 133 MHz PCI-X\n"); else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) info(" 66 MHz PCI-X\n"); @@ -1060,7 +1029,7 @@ static int enable_slot(struct hotplug_slot *hs) } attn_LED_blink(slot_cur); - + rc = set_bus(slot_cur); if (rc) { err("was not able to set the bus\n"); @@ -1076,8 +1045,7 @@ static int enable_slot(struct hotplug_slot *hs) rc = check_limitations(slot_cur); if (rc) { err("Adding this card exceeds the limitations of this bus.\n"); - err("(i.e., >1 133MHz cards running on same bus, or " - ">2 66 PCI cards running on same bus.\n"); + err("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus.\n"); err("Try hot-adding into another bus\n"); rc = -EINVAL; goto error_nopower; @@ -1101,12 +1069,10 @@ static int enable_slot(struct hotplug_slot *hs) !(SLOT_PWRGD(slot_cur->status))) err("power fault occurred trying to power up\n"); else if (SLOT_BUS_SPEED(slot_cur->status)) { - err("bus speed mismatch occurred. please check " - "current bus speed and card capability\n"); + err("bus speed mismatch occurred. please check current bus speed and card capability\n"); print_card_capability(slot_cur); } else if (SLOT_BUS_MODE(slot_cur->ext_status)) { - err("bus mode mismatch occurred. please check " - "current bus mode and card capability\n"); + err("bus mode mismatch occurred. please check current bus mode and card capability\n"); print_card_capability(slot_cur); } ibmphp_update_slot_info(slot_cur); @@ -1122,18 +1088,17 @@ static int enable_slot(struct hotplug_slot *hs) rc = slot_update(&slot_cur); if (rc) goto error_power; - + rc = -EINVAL; if (SLOT_POWER(slot_cur->status) && !(SLOT_PWRGD(slot_cur->status))) { err("power fault occurred trying to power up...\n"); goto error_power; } if (SLOT_POWER(slot_cur->status) && (SLOT_BUS_SPEED(slot_cur->status))) { - err("bus speed mismatch occurred. please check current bus " - "speed and card capability\n"); + err("bus speed mismatch occurred. please check current bus speed and card capability\n"); print_card_capability(slot_cur); goto error_power; - } + } /* Don't think this case will happen after above checks... * but just in case, for paranoia sake */ if (!(SLOT_POWER(slot_cur->status))) { @@ -1141,7 +1106,7 @@ static int enable_slot(struct hotplug_slot *hs) goto error_power; } - slot_cur->func = kmalloc(sizeof(struct pci_func), GFP_KERNEL); + slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL); if (!slot_cur->func) { /* We cannot do update_slot_info here, since no memory for * kmalloc n.e.ways, and update_slot_info allocates some */ @@ -1149,7 +1114,6 @@ static int enable_slot(struct hotplug_slot *hs) rc = -ENOMEM; goto error_power; } - memset(slot_cur->func, 0, sizeof(struct pci_func)); slot_cur->func->busno = slot_cur->bus; slot_cur->func->device = slot_cur->device; for (i = 0; i < 4; i++) @@ -1185,7 +1149,7 @@ static int enable_slot(struct hotplug_slot *hs) ibmphp_print_test(); rc = ibmphp_update_slot_info(slot_cur); exit: - ibmphp_unlock_operations(); + ibmphp_unlock_operations(); return rc; error_nopower: @@ -1221,7 +1185,7 @@ static int ibmphp_disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; int rc; - + ibmphp_lock_operations(); rc = ibmphp_do_disable_slot(slot); ibmphp_unlock_operations(); @@ -1233,16 +1197,16 @@ int ibmphp_do_disable_slot(struct slot *slot_cur) int rc; u8 flag; - debug("DISABLING SLOT...\n"); - + debug("DISABLING SLOT...\n"); + if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) { return -ENODEV; } - + flag = slot_cur->flag; - slot_cur->flag = TRUE; + slot_cur->flag = 1; - if (flag == TRUE) { + if (flag == 1) { rc = validate(slot_cur, DISABLE); /* checking if powered off already & valid slot # */ if (rc) @@ -1251,25 +1215,25 @@ int ibmphp_do_disable_slot(struct slot *slot_cur) attn_LED_blink(slot_cur); if (slot_cur->func == NULL) { - /* We need this for fncs's that were there on bootup */ - slot_cur->func = kmalloc(sizeof(struct pci_func), GFP_KERNEL); + /* We need this for functions that were there on bootup */ + slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL); if (!slot_cur->func) { err("out of system memory\n"); rc = -ENOMEM; goto error; } - memset(slot_cur->func, 0, sizeof(struct pci_func)); slot_cur->func->busno = slot_cur->bus; slot_cur->func->device = slot_cur->device; } ibm_unconfigure_device(slot_cur->func); - - /* If we got here from latch suddenly opening on operating card or - a power fault, there's no power to the card, so cannot - read from it to determine what resources it occupied. This operation - is forbidden anyhow. The best we can do is remove it from kernel - lists at least */ + + /* + * If we got here from latch suddenly opening on operating card or + * a power fault, there's no power to the card, so cannot + * read from it to determine what resources it occupied. This operation + * is forbidden anyhow. The best we can do is remove it from kernel + * lists at least */ if (!flag) { attn_off(slot_cur); @@ -1306,13 +1270,12 @@ error: rc = -EFAULT; goto exit; } - if (flag) + if (flag) ibmphp_update_slot_info(slot_cur); goto exit; } struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = ibmphp_disable_slot, @@ -1321,8 +1284,6 @@ struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_present, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, /* .get_max_adapter_speed = get_max_adapter_speed, .get_bus_name_status = get_bus_name, */ @@ -1384,7 +1345,7 @@ static int __init ibmphp_init(void) debug("AFTER Resource & EBDA INITIALIZATIONS\n"); max_slots = get_max_slots(); - + if ((rc = ibmphp_register_pci())) goto error; @@ -1398,10 +1359,6 @@ static int __init ibmphp_init(void) goto error; } - /* lock ourselves into memory with a module - * count of -1 so that no one can unload us. */ - module_put(THIS_MODULE); - exit: return rc; diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index aea1187c73a..0f65ac55543 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -28,7 +28,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> @@ -72,13 +71,7 @@ static int ebda_rio_table (void); static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void) { - struct ebda_hpc_list *list; - - list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; + return kzalloc(sizeof(struct ebda_hpc_list), GFP_KERNEL); } static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) @@ -87,21 +80,18 @@ static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) struct ebda_hpc_slot *slots; struct ebda_hpc_bus *buses; - controller = kmalloc (sizeof (struct controller), GFP_KERNEL); + controller = kzalloc(sizeof(struct controller), GFP_KERNEL); if (!controller) goto error; - memset (controller, 0, sizeof (*controller)); - slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); + slots = kcalloc(slot_count, sizeof(struct ebda_hpc_slot), GFP_KERNEL); if (!slots) goto error_contr; - memset (slots, 0, sizeof (*slots) * slot_count); controller->slots = slots; - buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); + buses = kcalloc(bus_count, sizeof(struct ebda_hpc_bus), GFP_KERNEL); if (!buses) goto error_slots; - memset (buses, 0, sizeof (*buses) * bus_count); controller->buses = buses; return controller; @@ -122,45 +112,31 @@ static void free_ebda_hpc (struct controller *controller) static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void) { - struct ebda_rsrc_list *list; - - list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; + return kzalloc(sizeof(struct ebda_rsrc_list), GFP_KERNEL); } static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) { - struct ebda_pci_rsrc *resource; - - resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); - if (!resource) - return NULL; - memset (resource, 0, sizeof (*resource)); - return resource; + return kzalloc(sizeof(struct ebda_pci_rsrc), GFP_KERNEL); } static void __init print_bus_info (void) { struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); - debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); - debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); - debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); - debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); - debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); - - debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv); - debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv); - debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix); - debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix); - debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix); + + list_for_each_entry(ptr, &bus_info_head, bus_info_list) { + debug ("%s - slot_min = %x\n", __func__, ptr->slot_min); + debug ("%s - slot_max = %x\n", __func__, ptr->slot_max); + debug ("%s - slot_count = %x\n", __func__, ptr->slot_count); + debug ("%s - bus# = %x\n", __func__, ptr->busno); + debug ("%s - current_speed = %x\n", __func__, ptr->current_speed); + debug ("%s - controller_id = %x\n", __func__, ptr->controller_id); + + debug ("%s - slots_at_33_conv = %x\n", __func__, ptr->slots_at_33_conv); + debug ("%s - slots_at_66_conv = %x\n", __func__, ptr->slots_at_66_conv); + debug ("%s - slots_at_66_pcix = %x\n", __func__, ptr->slots_at_66_pcix); + debug ("%s - slots_at_100_pcix = %x\n", __func__, ptr->slots_at_100_pcix); + debug ("%s - slots_at_133_pcix = %x\n", __func__, ptr->slots_at_133_pcix); } } @@ -168,16 +144,14 @@ static void __init print_bus_info (void) static void print_lo_info (void) { struct rio_detail *ptr; - struct list_head *ptr1; - debug ("print_lo_info ----\n"); - list_for_each (ptr1, &rio_lo_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + debug ("print_lo_info ----\n"); + list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) { + debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __func__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __func__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __func__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __func__, ptr->chassis_num); } } @@ -185,16 +159,14 @@ static void print_lo_info (void) static void print_vg_info (void) { struct rio_detail *ptr; - struct list_head *ptr1; - debug ("%s ---\n", __FUNCTION__); - list_for_each (ptr1, &rio_vg_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + debug ("%s ---\n", __func__); + list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) { + debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __func__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __func__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __func__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __func__, ptr->chassis_num); } } @@ -202,80 +174,70 @@ static void print_vg_info (void) static void __init print_ebda_pci_rsrc (void) { struct ebda_pci_rsrc *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { - ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); + list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) { + debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + __func__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); } } static void __init print_ibm_slot (void) { struct slot *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &ibmphp_slot_head) { - ptr = list_entry (ptr1, struct slot, ibm_slot_list); - debug ("%s - slot_number: %x\n", __FUNCTION__, ptr->number); + list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) { + debug ("%s - slot_number: %x\n", __func__, ptr->number); } } static void __init print_opt_vg (void) { struct opt_rio *ptr; - struct list_head *ptr1; - debug ("%s ---\n", __FUNCTION__); - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); - debug ("%s - rio_type %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - chassis_num: %x\n", __FUNCTION__, ptr->chassis_num); - debug ("%s - first_slot_num: %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - middle_num: %x\n", __FUNCTION__, ptr->middle_num); + debug ("%s ---\n", __func__); + list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) { + debug ("%s - rio_type %x\n", __func__, ptr->rio_type); + debug ("%s - chassis_num: %x\n", __func__, ptr->chassis_num); + debug ("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num); + debug ("%s - middle_num: %x\n", __func__, ptr->middle_num); } } static void __init print_ebda_hpc (void) { struct controller *hpc_ptr; - struct list_head *ptr1; u16 index; - list_for_each (ptr1, &ebda_hpc_head) { - - hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); - + list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) { for (index = 0; index < hpc_ptr->slot_count; index++) { - debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); - debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); - debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); - debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); + debug ("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num); + debug ("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num); + debug ("%s - index into ctlr addr: %x\n", __func__, hpc_ptr->slots[index].ctl_index); + debug ("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap); } for (index = 0; index < hpc_ptr->bus_count; index++) { - debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); + debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num); } - debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); + debug ("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type); switch (hpc_ptr->ctlr_type) { case 1: - debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); - debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + debug ("%s - bus: %x\n", __func__, hpc_ptr->u.pci_ctlr.bus); + debug ("%s - dev_fun: %x\n", __func__, hpc_ptr->u.pci_ctlr.dev_fun); + debug ("%s - irq: %x\n", __func__, hpc_ptr->irq); break; case 0: - debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); - debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + debug ("%s - io_start: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_start); + debug ("%s - io_end: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_end); + debug ("%s - irq: %x\n", __func__, hpc_ptr->irq); break; case 2: case 4: - debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); - debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + debug ("%s - wpegbbar: %lx\n", __func__, hpc_ptr->u.wpeg_ctlr.wpegbbar); + debug ("%s - i2c_addr: %x\n", __func__, hpc_ptr->u.wpeg_ctlr.i2c_addr); + debug ("%s - irq: %x\n", __func__, hpc_ptr->irq); break; } } @@ -283,7 +245,7 @@ static void __init print_ebda_hpc (void) int __init ibmphp_access_ebda (void) { - u8 format, num_ctlrs, rio_complete, hs_complete; + u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz; u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base; int rc = 0; @@ -297,14 +259,29 @@ int __init ibmphp_access_ebda (void) ebda_seg = readw (io_mem); iounmap (io_mem); debug ("returned ebda segment: %x\n", ebda_seg); - - io_mem = ioremap (ebda_seg<<4, 65000); + + io_mem = ioremap(ebda_seg<<4, 1); + if (!io_mem) + return -ENOMEM; + ebda_sz = readb(io_mem); + iounmap(io_mem); + debug("ebda size: %d(KiB)\n", ebda_sz); + if (ebda_sz == 0) + return -ENOMEM; + + io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024)); if (!io_mem ) return -ENOMEM; next_offset = 0x180; for (;;) { offset = next_offset; + + /* Make sure what we read is still in the mapped section */ + if (WARN(offset > (ebda_sz * 1024 - 4), + "ibmphp_ebda: next read is beyond ebda_sz\n")) + break; + next_offset = readw (io_mem + offset); /* offset of next blk */ offset += 2; @@ -333,7 +310,7 @@ int __init ibmphp_access_ebda (void) re = readw (io_mem + sub_addr); /* next sub blk */ sub_addr += 2; - rc_id = readw (io_mem + sub_addr); /* sub blk id */ + rc_id = readw (io_mem + sub_addr); /* sub blk id */ sub_addr += 2; if (rc_id != 0x5243) @@ -353,7 +330,7 @@ int __init ibmphp_access_ebda (void) debug ("info about hpc descriptor---\n"); debug ("hot blk format: %x\n", format); debug ("num of controller: %x\n", num_ctlrs); - debug ("offset of hpc data structure enteries: %x\n ", sub_addr); + debug ("offset of hpc data structure entries: %x\n ", sub_addr); sub_addr = base + re; /* re sub blk */ /* FIXME: rc is never used/checked */ @@ -382,7 +359,7 @@ int __init ibmphp_access_ebda (void) debug ("info about rsrc descriptor---\n"); debug ("format: %x\n", format); debug ("num of rsrc: %x\n", num_entries); - debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); + debug ("offset of rsrc data structure entries: %x\n ", sub_addr); hs_complete = 1; } else { @@ -390,15 +367,16 @@ int __init ibmphp_access_ebda (void) debug ("now enter io table ---\n"); debug ("rio blk id: %x\n", blk_id); - rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); - if (!rio_table_ptr) - return -ENOMEM; - memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); + rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL); + if (!rio_table_ptr) { + rc = -ENOMEM; + goto out; + } rio_table_ptr->ver_num = readb (io_mem + offset); rio_table_ptr->scal_count = readb (io_mem + offset + 1); rio_table_ptr->riodev_count = readb (io_mem + offset + 2); rio_table_ptr->offset = offset +3 ; - + debug("info about rio table hdr ---\n"); debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, @@ -445,10 +423,9 @@ static int __init ebda_rio_table (void) // we do concern about rio details for (i = 0; i < rio_table_ptr->riodev_count; i++) { - rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL); + rio_detail_ptr = kzalloc(sizeof(struct rio_detail), GFP_KERNEL); if (!rio_detail_ptr) return -ENOMEM; - memset (rio_detail_ptr, 0, sizeof (struct rio_detail)); rio_detail_ptr->rio_node_id = readb (io_mem + offset); rio_detail_ptr->bbar = readl (io_mem + offset + 1); rio_detail_ptr->rio_type = readb (io_mem + offset + 5); @@ -463,12 +440,12 @@ static int __init ebda_rio_table (void) rio_detail_ptr->chassis_num = readb (io_mem + offset + 14); // debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); //create linked list of chassis - if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) + if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head); - //create linked list of expansion box - else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) + //create linked list of expansion box + else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head); - else + else // not in my concern kfree (rio_detail_ptr); offset += 15; @@ -479,17 +456,15 @@ static int __init ebda_rio_table (void) } /* - * reorganizing linked list of chassis + * reorganizing linked list of chassis */ static struct opt_rio *search_opt_vg (u8 chassis_num) { struct opt_rio *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); + list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) { if (ptr->chassis_num == chassis_num) return ptr; - } + } return NULL; } @@ -497,42 +472,37 @@ static int __init combine_wpg_for_chassis (void) { struct opt_rio *opt_rio_ptr = NULL; struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_vg_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + + list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) { opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num); if (!opt_rio_ptr) { - opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL); + opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL); if (!opt_rio_ptr) return -ENOMEM; - memset (opt_rio_ptr, 0, sizeof (struct opt_rio)); opt_rio_ptr->rio_type = rio_detail_ptr->rio_type; opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num; opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num; opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num; list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head); - } else { + } else { opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num); opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num); - } + } } print_opt_vg (); - return 0; -} + return 0; +} /* - * reorgnizing linked list of expansion box + * reorganizing linked list of expansion box */ static struct opt_rio_lo *search_opt_lo (u8 chassis_num) { struct opt_rio_lo *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_lo_head) { - ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list); + list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) { if (ptr->chassis_num == chassis_num) return ptr; - } + } return NULL; } @@ -540,56 +510,50 @@ static int combine_wpg_for_expansion (void) { struct opt_rio_lo *opt_rio_lo_ptr = NULL; struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_lo_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + + list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) { opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num); if (!opt_rio_lo_ptr) { - opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL); + opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL); if (!opt_rio_lo_ptr) return -ENOMEM; - memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo)); opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type; opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num; opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num; opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num; opt_rio_lo_ptr->pack_count = 1; - + list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head); - } else { + } else { opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num); opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num); opt_rio_lo_ptr->pack_count = 2; - } + } } - return 0; + return 0; } - + /* Since we don't know the max slot number per each chassis, hence go * through the list of all chassis to find out the range - * Arguments: slot_num, 1st slot number of the chassis we think we are on, - * var (0 = chassis, 1 = expansion box) + * Arguments: slot_num, 1st slot number of the chassis we think we are on, + * var (0 = chassis, 1 = expansion box) */ static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) { struct opt_rio *opt_vg_ptr = NULL; struct opt_rio_lo *opt_lo_ptr = NULL; - struct list_head *ptr = NULL; int rc = 0; if (!var) { - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { + list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) { + if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { rc = -ENODEV; break; } } } else { - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) { if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) { rc = -ENODEV; break; @@ -599,29 +563,25 @@ static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) return rc; } -static struct opt_rio_lo * find_rxe_num (u8 slot_num) +static struct opt_rio_lo *find_rxe_num (u8 slot_num) { struct opt_rio_lo *opt_lo_ptr; - struct list_head *ptr; - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) { //check to see if this slot_num belongs to expansion box - if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) + if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) return opt_lo_ptr; } return NULL; } -static struct opt_rio * find_chassis_num (u8 slot_num) +static struct opt_rio *find_chassis_num (u8 slot_num) { struct opt_rio *opt_vg_ptr; - struct list_head *ptr; - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - //check to see if this slot_num belongs to chassis - if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) + list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) { + //check to see if this slot_num belongs to chassis + if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) return opt_vg_ptr; } return NULL; @@ -633,24 +593,25 @@ static struct opt_rio * find_chassis_num (u8 slot_num) static u8 calculate_first_slot (u8 slot_num) { u8 first_slot = 1; - struct list_head * list; - struct slot * slot_cur; - - list_for_each (list, &ibmphp_slot_head) { - slot_cur = list_entry (list, struct slot, ibm_slot_list); + struct slot *slot_cur; + + list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { if (slot_cur->ctrl) { - if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) + if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) first_slot = slot_cur->ctrl->ending_slot_num; } - } + } return first_slot + 1; } -static char *create_file_name (struct slot * slot_cur) + +#define SLOT_NAME_SIZE 30 + +static char *create_file_name (struct slot *slot_cur) { struct opt_rio *opt_vg_ptr = NULL; struct opt_rio_lo *opt_lo_ptr = NULL; - static char str[30]; + static char str[SLOT_NAME_SIZE]; int which = 0; /* rxe = 1, chassis = 0 */ u8 number = 1; /* either chassis or rxe # */ u8 first_slot = 1; @@ -661,11 +622,11 @@ static char *create_file_name (struct slot * slot_cur) err ("Structure passed is empty\n"); return NULL; } - + slot_num = slot_cur->number; memset (str, 0, sizeof(str)); - + if (rio_table_ptr) { if (rio_table_ptr->ver_num == 3) { opt_vg_ptr = find_chassis_num (slot_num); @@ -699,7 +660,7 @@ static char *create_file_name (struct slot * slot_cur) /* if both NULL and we DO have correct RIO table in BIOS */ return NULL; } - } + } if (!flag) { if (slot_cur->ctrl->ctlr_type == 4) { first_slot = calculate_first_slot (slot_num); @@ -762,7 +723,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); slot->ctrl = NULL; slot->bus_on = NULL; @@ -793,7 +753,7 @@ static int __init ebda_rsrc_controller (void) struct bus_info *bus_info_ptr1, *bus_info_ptr2; int rc; struct slot *tmp_slot; - struct list_head *list; + char name[SLOT_NAME_SIZE]; addr = hpc_list_ptr->phys_addr; for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { @@ -824,7 +784,7 @@ static int __init ebda_rsrc_controller (void) hpc_ptr->ctlr_relative_id = ctlr; hpc_ptr->slot_count = slot_num; hpc_ptr->bus_count = bus_num; - debug ("now enter ctlr data struture ---\n"); + debug ("now enter ctlr data structure ---\n"); debug ("ctlr id: %x\n", ctlr_id); debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); debug ("count of slots controlled by this ctlr: %x\n", slot_num); @@ -838,16 +798,15 @@ static int __init ebda_rsrc_controller (void) slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); - // create bus_info lined list --- if only one slot per bus: slot_min = slot_max + // create bus_info lined list --- if only one slot per bus: slot_min = slot_max bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); if (!bus_info_ptr2) { - bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); + bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL); if (!bus_info_ptr1) { rc = -ENOMEM; goto error_no_hp_slot; } - memset (bus_info_ptr1, 0, sizeof (struct bus_info)); bus_info_ptr1->slot_min = slot_ptr->slot_num; bus_info_ptr1->slot_max = slot_ptr->slot_num; bus_info_ptr1->slot_count += 1; @@ -855,9 +814,9 @@ static int __init ebda_rsrc_controller (void) bus_info_ptr1->index = bus_index++; bus_info_ptr1->current_speed = 0xff; bus_info_ptr1->current_bus_mode = 0xff; - + bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; - + list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); } else { @@ -892,7 +851,7 @@ static int __init ebda_rsrc_controller (void) bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv; bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix; bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix; - bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; + bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; } bus_ptr++; } @@ -905,7 +864,7 @@ static int __init ebda_rsrc_controller (void) hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); hpc_ptr->irq = readb (io_mem + addr + 2); addr += 3; - debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", + debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", hpc_ptr->u.pci_ctlr.bus, hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq); break; @@ -946,34 +905,25 @@ static int __init ebda_rsrc_controller (void) // register slots with hpc core as well as create linked list of ibm slot for (index = 0; index < hpc_ptr->slot_count; index++) { - hp_slot_ptr = kmalloc(sizeof(*hp_slot_ptr), GFP_KERNEL); + hp_slot_ptr = kzalloc(sizeof(*hp_slot_ptr), GFP_KERNEL); if (!hp_slot_ptr) { rc = -ENOMEM; goto error_no_hp_slot; } - memset(hp_slot_ptr, 0, sizeof(*hp_slot_ptr)); - hp_slot_ptr->info = kmalloc (sizeof(struct hotplug_slot_info), GFP_KERNEL); + hp_slot_ptr->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); if (!hp_slot_ptr->info) { rc = -ENOMEM; goto error_no_hp_info; } - memset(hp_slot_ptr->info, 0, sizeof(struct hotplug_slot_info)); - hp_slot_ptr->name = kmalloc(30, GFP_KERNEL); - if (!hp_slot_ptr->name) { - rc = -ENOMEM; - goto error_no_hp_name; - } - - tmp_slot = kmalloc(sizeof(*tmp_slot), GFP_KERNEL); + tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL); if (!tmp_slot) { rc = -ENOMEM; goto error_no_slot; } - memset(tmp_slot, 0, sizeof(*tmp_slot)); - tmp_slot->flag = TRUE; + tmp_slot->flag = 1; tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap; if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX) @@ -982,7 +932,7 @@ static int __init ebda_rsrc_controller (void) tmp_slot->supported_speed = 2; else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX) tmp_slot->supported_speed = 1; - + if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP) tmp_slot->supported_bus_mode = 1; else @@ -993,6 +943,7 @@ static int __init ebda_rsrc_controller (void) bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); if (!bus_info_ptr1) { + kfree(tmp_slot); rc = -ENODEV; goto error; } @@ -1026,11 +977,10 @@ static int __init ebda_rsrc_controller (void) } /* each hpc */ - list_for_each (list, &ibmphp_slot_head) { - tmp_slot = list_entry (list, struct slot, ibm_slot_list); - - snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); - pci_hp_register (tmp_slot->hotplug_slot); + list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) { + snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot)); + pci_hp_register(tmp_slot->hotplug_slot, + pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name); } print_ebda_hpc (); @@ -1040,8 +990,6 @@ static int __init ebda_rsrc_controller (void) error: kfree (hp_slot_ptr->private); error_no_slot: - kfree (hp_slot_ptr->name); -error_no_hp_name: kfree (hp_slot_ptr->info); error_no_hp_info: kfree (hp_slot_ptr); @@ -1052,7 +1000,7 @@ error_no_hpc: return rc; } -/* +/* * map info (bus, devfun, start addr, end addr..) of i/o, memory, * pfm from the physical addr to a list of resource. */ @@ -1109,7 +1057,7 @@ static int __init ebda_rsrc_rsrc (void) addr += 10; debug ("rsrc from mem or pfm ---\n"); - debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); @@ -1129,10 +1077,8 @@ u16 ibmphp_get_total_controllers (void) struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) { struct slot *slot; - struct list_head *list; - list_for_each (list, &ibmphp_slot_head) { - slot = list_entry (list, struct slot, ibm_slot_list); + list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) { if (slot->number == physical_num) return slot; } @@ -1148,11 +1094,9 @@ struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) struct bus_info *ibmphp_find_same_bus_num (u32 num) { struct bus_info *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) + list_for_each_entry(ptr, &bus_info_head, bus_info_list) { + if (ptr->busno == num) return ptr; } return NULL; @@ -1164,11 +1108,9 @@ struct bus_info *ibmphp_find_same_bus_num (u32 num) int ibmphp_get_bus_index (u8 num) { struct bus_info *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) + list_for_each_entry(ptr, &bus_info_head, bus_info_list) { + if (ptr->busno == num) return ptr->index; } return -ENODEV; @@ -1226,7 +1168,7 @@ static struct pci_device_id id_table[] = { .subdevice = HPC_SUBSYSTEM_ID, .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), }, {} -}; +}; MODULE_DEVICE_TABLE(pci, id_table); @@ -1240,11 +1182,9 @@ static struct pci_driver ibmphp_driver = { int ibmphp_register_pci (void) { struct controller *ctrl; - struct list_head *tmp; int rc = 0; - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) { if (ctrl->ctlr_type == 1) { rc = pci_register_driver(&ibmphp_driver); break; @@ -1252,15 +1192,13 @@ int ibmphp_register_pci (void) } return rc; } -static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) +static int ibmphp_probe (struct pci_dev *dev, const struct pci_device_id *ids) { struct controller *ctrl; - struct list_head *tmp; debug ("inside ibmphp_probe\n"); - - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + + list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) { if (ctrl->ctlr_type == 1) { if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) { ctrl->ctrl_dev = dev; @@ -1272,4 +1210,3 @@ static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) } return -ENODEV; } - diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index 1a3eb8d3d4c..a936022956e 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -32,11 +32,14 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/mutex.h> +#include <linux/sched.h> +#include <linux/semaphore.h> +#include <linux/kthread.h> #include "ibmphp.h" -static int to_debug = FALSE; +static int to_debug = 0; #define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) //---------------------------------------------------------------------------- @@ -93,18 +96,17 @@ static int to_debug = FALSE; //---------------------------------------------------------------------------- // macro utilities //---------------------------------------------------------------------------- -// if bits 20,22,25,26,27,29,30 are OFF return TRUE -#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) +// if bits 20,22,25,26,27,29,30 are OFF return 1 +#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? 0 : 1)) //---------------------------------------------------------------------------- // global variables //---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; -static struct semaphore sem_hpcaccess; // lock access to HPC +static struct mutex sem_hpcaccess; // lock access to HPC static struct semaphore semOperations; // lock all operations and // access to data structures static struct semaphore sem_exit; // make sure polling thread goes away +static struct task_struct *ibmphp_poll_thread; //---------------------------------------------------------------------------- // local function prototypes //---------------------------------------------------------------------------- @@ -114,10 +116,9 @@ static u8 hpc_writecmdtoindex (u8, u8); static u8 hpc_readcmdtoindex (u8, u8); static void get_hpc_access (void); static void free_hpc_access (void); -static void poll_hpc (void); +static int poll_hpc(void *data); static int process_changeinstatus (struct slot *, struct slot *); static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *); //---------------------------------------------------------------------------- @@ -129,16 +130,14 @@ static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u *---------------------------------------------------------------------*/ void __init ibmphp_hpc_initvars (void) { - debug ("%s - Entry\n", __FUNCTION__); + debug ("%s - Entry\n", __func__); - init_MUTEX (&sem_hpcaccess); - init_MUTEX (&semOperations); - init_MUTEX_LOCKED (&sem_exit); - to_debug = FALSE; - ibmphp_shutdown = FALSE; - tid_poll = 0; + mutex_init(&sem_hpcaccess); + sema_init(&semOperations, 1); + sema_init(&sem_exit, 0); + to_debug = 0; - debug ("%s - Exit\n", __FUNCTION__); + debug ("%s - Exit\n", __func__); } /*---------------------------------------------------------------------- @@ -156,7 +155,7 @@ static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 unsigned long ultemp; unsigned long data; // actual data HILO format - debug_polling ("%s - Entry WPGBbar[%p] index[%x] \n", __FUNCTION__, WPGBbar, index); + debug_polling ("%s - Entry WPGBbar[%p] index[%x] \n", __func__, WPGBbar, index); //-------------------------------------------------------------------- // READ - step 1 @@ -215,7 +214,7 @@ static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 i--; } if (i == 0) { - debug ("%s - Error : WPG timeout\n", __FUNCTION__); + debug ("%s - Error : WPG timeout\n", __func__); return HPC_ERROR; } //-------------------------------------------------------------------- @@ -243,7 +242,7 @@ static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 status = (u8) data; - debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); + debug_polling ("%s - Exit index[%x] status[%x]\n", __func__, index, status); return (status); } @@ -259,12 +258,12 @@ static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 { u8 rc; void __iomem *wpg_addr; // base addr + offset - unsigned long wpg_data; // data to/from WPG LOHI format + unsigned long wpg_data; // data to/from WPG LOHI format unsigned long ultemp; unsigned long data; // actual data HILO format int i; - debug_polling ("%s - Entry WPGBbar[%p] index[%x] cmd[%x]\n", __FUNCTION__, WPGBbar, index, cmd); + debug_polling ("%s - Entry WPGBbar[%p] index[%x] cmd[%x]\n", __func__, WPGBbar, index, cmd); rc = 0; //-------------------------------------------------------------------- @@ -326,7 +325,7 @@ static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 i--; } if (i == 0) { - debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); + debug ("%s - Exit Error:WPG timeout\n", __func__); rc = HPC_ERROR; } @@ -347,12 +346,12 @@ static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 rc = HPC_ERROR; } - debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); + debug_polling ("%s Exit rc[%x]\n", __func__, rc); return (rc); } //------------------------------------------------------------ -// Read from ISA type HPC +// Read from ISA type HPC //------------------------------------------------------------ static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset) { @@ -373,7 +372,7 @@ static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data) { u16 start_address; u16 port_address; - + start_address = ctlr_ptr->u.isa_ctlr.io_start; port_address = start_address + (u16) offset; outb (data, port_address); @@ -529,12 +528,12 @@ static u8 hpc_readcmdtoindex (u8 cmd, u8 index) * * Action: issue a READ command to HPC * -* Input: pslot - can not be NULL for READ_ALLSTAT +* Input: pslot - cannot be NULL for READ_ALLSTAT * pstatus - can be NULL for READ_ALLSTAT * * Return 0 or error codes *---------------------------------------------------------------------*/ -int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +int ibmphp_hpc_readslot (struct slot *pslot, u8 cmd, u8 *pstatus) { void __iomem *wpg_bbar = NULL; struct controller *ctlr_ptr; @@ -543,12 +542,12 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) int rc = 0; int busindex; - debug_polling ("%s - Entry pslot[%p] cmd[%x] pstatus[%p]\n", __FUNCTION__, pslot, cmd, pstatus); + debug_polling ("%s - Entry pslot[%p] cmd[%x] pstatus[%p]\n", __func__, pslot, cmd, pstatus); if ((pslot == NULL) || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { rc = -EINVAL; - err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); + err ("%s - Error invalid pointer, rc[%d]\n", __func__, rc); return rc; } @@ -556,7 +555,7 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) busindex = ibmphp_get_bus_index (pslot->bus); if (busindex < 0) { rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + err ("%s - Exit Error:invalid bus, rc[%d]\n", __func__, rc); return rc; } else index = (u8) busindex; @@ -567,7 +566,7 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) if (index == HPC_ERROR) { rc = -EINVAL; - err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); + err ("%s - Exit Error:invalid index, rc[%d]\n", __func__, rc); return rc; } @@ -643,7 +642,7 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); } else { - err ("%s - Error ctrl_read failed\n", __FUNCTION__); + err ("%s - Error ctrl_read failed\n", __func__); rc = -EINVAL; break; } @@ -657,14 +656,14 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) //-------------------------------------------------------------------- // cleanup //-------------------------------------------------------------------- - + // remove physical to logical address mapping if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) iounmap (wpg_bbar); - + free_hpc_access (); - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + debug_polling ("%s - Exit rc[%d]\n", __func__, rc); return rc; } @@ -673,7 +672,7 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) * * Action: issue a WRITE command to HPC *---------------------------------------------------------------------*/ -int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +int ibmphp_hpc_writeslot (struct slot *pslot, u8 cmd) { void __iomem *wpg_bbar = NULL; struct controller *ctlr_ptr; @@ -683,10 +682,10 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) int rc = 0; int timeout; - debug_polling ("%s - Entry pslot[%p] cmd[%x]\n", __FUNCTION__, pslot, cmd); + debug_polling ("%s - Entry pslot[%p] cmd[%x]\n", __func__, pslot, cmd); if (pslot == NULL) { rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + err ("%s - Error Exit rc[%d]\n", __func__, rc); return rc; } @@ -696,7 +695,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) busindex = ibmphp_get_bus_index (pslot->bus); if (busindex < 0) { rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + err ("%s - Exit Error:invalid bus, rc[%d]\n", __func__, rc); return rc; } else index = (u8) busindex; @@ -707,7 +706,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) if (index == HPC_ERROR) { rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + err ("%s - Error Exit rc[%d]\n", __func__, rc); return rc; } @@ -721,7 +720,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); - debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, + debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __func__, ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, ctlr_ptr->u.wpeg_ctlr.i2c_addr); } @@ -737,22 +736,22 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) // check controller is still not working on the command //-------------------------------------------------------------------- timeout = CMD_COMPLETE_TOUT_SEC; - done = FALSE; + done = 0; while (!done) { rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); if (!rc) { if (NEEDTOCHECK_CMDSTATUS (cmd)) { if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) - done = TRUE; + done = 1; } else - done = TRUE; + done = 1; } if (!done) { msleep(1000); if (timeout < 1) { - done = TRUE; - err ("%s - Error command complete timeout\n", __FUNCTION__); + done = 1; + err ("%s - Error command complete timeout\n", __func__); rc = -EFAULT; } else timeout--; @@ -767,7 +766,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) iounmap (wpg_bbar); free_hpc_access (); - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + debug_polling ("%s - Exit rc[%d]\n", __func__, rc); return rc; } @@ -778,7 +777,7 @@ int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) *---------------------------------------------------------------------*/ static void get_hpc_access (void) { - down (&sem_hpcaccess); + mutex_lock(&sem_hpcaccess); } /*---------------------------------------------------------------------- @@ -786,7 +785,7 @@ static void get_hpc_access (void) *---------------------------------------------------------------------*/ void free_hpc_access (void) { - up (&sem_hpcaccess); + mutex_unlock(&sem_hpcaccess); } /*---------------------------------------------------------------------- @@ -797,7 +796,7 @@ void free_hpc_access (void) void ibmphp_lock_operations (void) { down (&semOperations); - to_debug = TRUE; + to_debug = 1; } /*---------------------------------------------------------------------- @@ -805,10 +804,10 @@ void ibmphp_lock_operations (void) *---------------------------------------------------------------------*/ void ibmphp_unlock_operations (void) { - debug ("%s - Entry\n", __FUNCTION__); + debug ("%s - Entry\n", __func__); up (&semOperations); - to_debug = FALSE; - debug ("%s - Exit\n", __FUNCTION__); + to_debug = 0; + debug ("%s - Exit\n", __func__); } /*---------------------------------------------------------------------- @@ -817,7 +816,7 @@ void ibmphp_unlock_operations (void) #define POLL_LATCH_REGISTER 0 #define POLL_SLOTS 1 #define POLL_SLEEP 2 -static void poll_hpc (void) +static int poll_hpc(void *data) { struct slot myslot; struct slot *pslot = NULL; @@ -829,17 +828,14 @@ static void poll_hpc (void) int poll_count = 0; u8 ctrl_count = 0x00; - debug ("%s - Entry\n", __FUNCTION__); + debug ("%s - Entry\n", __func__); - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - + while (!kthread_should_stop()) { /* try to get the lock to do some kind of hardware access */ down (&semOperations); switch (poll_state) { - case POLL_LATCH_REGISTER: + case POLL_LATCH_REGISTER: oldlatchlow = curlatchlow; ctrl_count = 0x00; list_for_each (pslotlist, &ibmphp_slot_head) { @@ -894,25 +890,27 @@ static void poll_hpc (void) up (&semOperations); msleep(POLL_INTERVAL_SEC * 1000); - if (ibmphp_shutdown) - break; - + if (kthread_should_stop()) + goto out_sleep; + down (&semOperations); - + if (poll_count >= POLL_LATCH_CNT) { poll_count = 0; poll_state = POLL_SLOTS; } else poll_state = POLL_LATCH_REGISTER; break; - } + } /* give up the hardware semaphore */ up (&semOperations); /* sleep for a short time just for good measure */ +out_sleep: msleep(100); } up (&sem_exit); - debug ("%s - Exit\n", __FUNCTION__); + debug ("%s - Exit\n", __func__); + return 0; } @@ -935,40 +933,40 @@ static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) { u8 status; int rc = 0; - u8 disable = FALSE; - u8 update = FALSE; + u8 disable = 0; + u8 update = 0; debug ("process_changeinstatus - Entry pslot[%p], poldslot[%p]\n", pslot, poldslot); // bit 0 - HPC_SLOT_POWER if ((pslot->status & 0x01) != (poldslot->status & 0x01)) - update = TRUE; + update = 1; // bit 1 - HPC_SLOT_CONNECT // ignore // bit 2 - HPC_SLOT_ATTN if ((pslot->status & 0x04) != (poldslot->status & 0x04)) - update = TRUE; + update = 1; // bit 3 - HPC_SLOT_PRSNT2 // bit 4 - HPC_SLOT_PRSNT1 if (((pslot->status & 0x08) != (poldslot->status & 0x08)) || ((pslot->status & 0x10) != (poldslot->status & 0x10))) - update = TRUE; + update = 1; // bit 5 - HPC_SLOT_PWRGD if ((pslot->status & 0x20) != (poldslot->status & 0x20)) // OFF -> ON: ignore, ON -> OFF: disable slot - if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) - disable = TRUE; + if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) + disable = 1; // bit 6 - HPC_SLOT_BUS_SPEED // ignore // bit 7 - HPC_SLOT_LATCH if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { - update = TRUE; + update = 1; // OPEN -> CLOSE if (pslot->status & 0x80) { if (SLOT_PWRGD (pslot->status)) { @@ -977,25 +975,25 @@ static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) msleep(1000); rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); if (SLOT_PWRGD (status)) - update = TRUE; + update = 1; else // overwrite power in pslot to OFF pslot->status &= ~HPC_SLOT_POWER; } } - // CLOSE -> OPEN + // CLOSE -> OPEN else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) { - disable = TRUE; + disable = 1; } // else - ignore } // bit 4 - HPC_SLOT_BLINK_ATTN if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) - update = TRUE; + update = 1; if (disable) { debug ("process_changeinstatus - disable slot\n"); - pslot->flag = FALSE; + pslot->flag = 0; rc = ibmphp_do_disable_slot (pslot); } @@ -1003,7 +1001,7 @@ static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) ibmphp_update_slot_info (pslot); } - debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); + debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __func__, rc, disable, update); return rc; } @@ -1025,7 +1023,7 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) u8 mask; int rc = 0; - debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); + debug ("%s - Entry old[%x], new[%x]\n", __func__, old, new); // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { @@ -1035,60 +1033,33 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) if (pslot) { memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); + debug ("%s - call process_changeinstatus for slot[%d]\n", __func__, i); process_changeinstatus (pslot, &myslot); } else { rc = -EINVAL; - err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); + err ("%s - Error bad pointer for slot[%d]\n", __func__, i); } } } - debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + debug ("%s - Exit rc[%d]\n", __func__, rc); return rc; } /*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - -/*---------------------------------------------------------------------- * Name: ibmphp_hpc_start_poll_thread * * Action: start polling thread *---------------------------------------------------------------------*/ int __init ibmphp_hpc_start_poll_thread (void) { - int rc = 0; + debug ("%s - Entry\n", __func__); - debug ("%s - Entry\n", __FUNCTION__); - - tid_poll = kernel_thread (hpc_poll_thread, NULL, 0); - if (tid_poll < 0) { - err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; + ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll"); + if (IS_ERR(ibmphp_poll_thread)) { + err ("%s - Error, thread not started\n", __func__); + return PTR_ERR(ibmphp_poll_thread); } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; + return 0; } /*---------------------------------------------------------------------- @@ -1098,13 +1069,13 @@ int __init ibmphp_hpc_start_poll_thread (void) *---------------------------------------------------------------------*/ void __exit ibmphp_hpc_stop_poll_thread (void) { - debug ("%s - Entry\n", __FUNCTION__); + debug ("%s - Entry\n", __func__); - ibmphp_shutdown = TRUE; + kthread_stop(ibmphp_poll_thread); debug ("before locking operations \n"); ibmphp_lock_operations (); debug ("after locking operations \n"); - + // wait for poll thread to exit debug ("before sem_exit down \n"); down (&sem_exit); @@ -1119,7 +1090,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void) up (&sem_exit); debug ("after sem exit up\n"); - debug ("%s - Exit\n", __FUNCTION__); + debug ("%s - Exit\n", __func__); } /*---------------------------------------------------------------------- @@ -1131,10 +1102,10 @@ void __exit ibmphp_hpc_stop_poll_thread (void) * Value: *---------------------------------------------------------------------*/ static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar, - u8 * pstatus) + u8 *pstatus) { int rc = 0; - u8 done = FALSE; + u8 done = 0; debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); @@ -1142,14 +1113,14 @@ static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, v *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); if (*pstatus == HPC_ERROR) { rc = HPC_ERROR; - done = TRUE; + done = 1; } if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) - done = TRUE; + done = 1; if (!done) { msleep(1000); if (timeout < 1) { - done = TRUE; + done = 1; err ("HPCreadslot - Error ctlr timeout\n"); rc = HPC_ERROR; } else diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index b1ba429e0a2..2fd296706ce 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -1,8 +1,8 @@ /* * IBM Hot Plug Controller Driver - * + * * Written By: Irene Zubarev, IBM Corporation - * + * * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2002 IBM Corp. * @@ -42,12 +42,12 @@ static u8 find_sec_number (u8 primary_busno, u8 slotno); /* * NOTE..... If BIOS doesn't provide default routing, we assign: - * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. + * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. * If adapter is bridged, then we assign 11 to it and devices behind it. * We also assign the same irq numbers for multi function devices. * These are PIC mode, so shouldn't matter n.e.ways (hopefully) */ -static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +static void assign_alt_irq (struct pci_func *cur_func, u8 class_code) { int j; for (j = 0; j < 4; j++) { @@ -71,11 +71,11 @@ static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) * Configures the device to be added (will allocate needed resources if it * can), the device can be a bridge or a regular pci device, can also be * multi-functional - * + * * Input: function to be added - * + * * TO DO: The error case with Multifunction device or multi function bridge, - * if there is an error, will need to go through all previous functions and + * if there is an error, will need to go through all previous functions and * unconfigure....or can add some code into unconfigure_card.... */ int ibmphp_configure_card (struct pci_func *func, u8 slotno) @@ -98,7 +98,7 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cur_func = func; /* We only get bus and device from IRQ routing table. So at this point, - * func->busno is correct, and func->device contains only device (at the 5 + * func->busno is correct, and func->device contains only device (at the 5 * highest bits) */ @@ -109,7 +109,7 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cur_func->function = function; - debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", + debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->function = %x\n", cur_func->busno, cur_func->device, cur_func->function); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); @@ -137,8 +137,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) "Please choose another device.\n", cur_func->device); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); + err ("The device %x is not supported for hot plugging. Please choose another device.\n", + cur_func->device); return -ENODEV; } switch (hdr_type) { @@ -151,7 +151,7 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cur_func->device, cur_func->busno); cleanup_count = 6; goto error; - } + } cur_func->next = NULL; function = 0x8; break; @@ -164,12 +164,11 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cleanup_count = 6; goto error; } - newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL); + newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL); if (!newfunc) { err ("out of system memory\n"); return -ENOMEM; } - memset (newfunc, 0, sizeof (struct pci_func)); newfunc->busno = cur_func->busno; newfunc->device = device; cur_func->next = newfunc; @@ -180,8 +179,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", + cur_func->device); return -ENODEV; } assign_alt_irq (cur_func, class_code); @@ -200,15 +199,14 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) } pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - flag = FALSE; + flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { - newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL); + newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL); if (!newfunc) { err ("out of system memory\n"); return -ENOMEM; } - memset (newfunc, 0, sizeof (struct pci_func)); newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) @@ -228,16 +226,15 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cleanup_count = 2; goto error; } - flag = TRUE; + flag = 1; } } - newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL); + newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL); if (!newfunc) { err ("out of system memory\n"); return -ENOMEM; } - memset (newfunc, 0, sizeof (struct pci_func)); newfunc->busno = cur_func->busno; newfunc->device = device; for (j = 0; j < 4; j++) @@ -250,8 +247,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) class >>= 8; debug ("class now is %x\n", class); if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", + cur_func->device); return -ENODEV; } @@ -275,16 +272,15 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cur_func->busno, device, function); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug ("after configuring bridge..., sec_number = %x\n", sec_number); - flag = FALSE; + flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { debug ("inside for loop, device is %x\n", i); - newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL); + newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL); if (!newfunc) { err (" out of system memory\n"); return -ENOMEM; } - memset (newfunc, 0, sizeof (struct pci_func)); newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) @@ -305,7 +301,7 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) cleanup_count = 2; goto error; } - flag = TRUE; + flag = 1; } } @@ -343,7 +339,7 @@ error: } /* - * This function configures the pci BARs of a single device. + * This function configures the pci BARs of a single device. * Input: pointer to the pci_func * Output: configured PCI, 0, or error */ @@ -368,24 +364,24 @@ static int configure_device (struct pci_func *func) struct resource_node *pfmem[6]; unsigned int devfn; - debug ("%s - inside\n", __FUNCTION__); + debug ("%s - inside\n", __func__); devfn = PCI_DEVFN(func->device, func->function); ibmphp_pci_bus->number = func->busno; for (count = 0; address[count]; count++) { /* for 6 BARs */ - /* not sure if i need this. per scott, said maybe need smth like this + /* not sure if i need this. per scott, said maybe need * something like this if devices don't adhere 100% to the spec, so don't want to write to the reserved bits - pcibios_read_config_byte(cur_func->busno, cur_func->device, + pcibios_read_config_byte(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, &tmp); if (tmp & 0x01) // IO - pcibios_write_config_dword(cur_func->busno, cur_func->device, + pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); else // Memory - pcibios_write_config_dword(cur_func->busno, cur_func->device, + pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); */ pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); @@ -405,13 +401,12 @@ static int configure_device (struct pci_func *func) debug ("len[count] in IO %x, count %d\n", len[count], count); - io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!io[count]) { err ("out of system memory\n"); return -ENOMEM; } - memset (io[count], 0, sizeof (struct resource_node)); io[count]->type = IO; io[count]->busno = func->busno; io[count]->devfunc = PCI_DEVFN(func->device, func->function); @@ -426,8 +421,8 @@ static int configure_device (struct pci_func *func) return -EIO; } pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); - - /* _______________This is for debugging purposes only_____________________ */ + + /* _______________This is for debugging purposes only_____________________ */ debug ("b4 writing, the IO address is %x\n", func->io[count]->start); pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); debug ("after writing.... the start address is %x\n", bar[count]); @@ -444,29 +439,27 @@ static int configure_device (struct pci_func *func) debug ("len[count] in PFMEM %x, count %d\n", len[count], count); - pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!pfmem[count]) { err ("out of system memory\n"); return -ENOMEM; } - memset (pfmem[count], 0, sizeof (struct resource_node)); pfmem[count]->type = PFMEM; pfmem[count]->busno = func->busno; pfmem[count]->devfunc = PCI_DEVFN(func->device, func->function); pfmem[count]->len = len[count]; - pfmem[count]->fromMem = FALSE; + pfmem[count]->fromMem = 0; if (ibmphp_check_resource (pfmem[count], 0) == 0) { ibmphp_add_resource (pfmem[count]); func->pfmem[count] = pfmem[count]; } else { - mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL); + mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL); if (!mem_tmp) { err ("out of system memory\n"); kfree (pfmem[count]); return -ENOMEM; } - memset (mem_tmp, 0, sizeof (struct resource_node)); mem_tmp->type = MEM; mem_tmp->busno = pfmem[count]->busno; mem_tmp->devfunc = pfmem[count]->devfunc; @@ -474,7 +467,7 @@ static int configure_device (struct pci_func *func) debug ("there's no pfmem... going into mem.\n"); if (ibmphp_check_resource (mem_tmp, 0) == 0) { ibmphp_add_resource (mem_tmp); - pfmem[count]->fromMem = TRUE; + pfmem[count]->fromMem = 1; pfmem[count]->rangeno = mem_tmp->rangeno; pfmem[count]->start = mem_tmp->start; pfmem[count]->end = mem_tmp->end; @@ -491,7 +484,7 @@ static int configure_device (struct pci_func *func) pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); - /*_______________This is for debugging purposes only______________________________*/ + /*_______________This is for debugging purposes only______________________________*/ debug ("b4 writing, start address is %x\n", func->pfmem[count]->start); pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); debug ("after writing, start address is %x\n", bar[count]); @@ -512,12 +505,11 @@ static int configure_device (struct pci_func *func) debug ("len[count] in Mem %x, count %d\n", len[count], count); - mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!mem[count]) { err ("out of system memory\n"); return -ENOMEM; } - memset (mem[count], 0, sizeof (struct resource_node)); mem[count]->type = MEM; mem[count]->busno = func->busno; mem[count]->devfunc = PCI_DEVFN(func->device, @@ -567,7 +559,7 @@ static int configure_device (struct pci_func *func) /****************************************************************************** * This routine configures a PCI-2-PCI bridge and the functions behind it * Parameters: pci_func - * Returns: + * Returns: ******************************************************************************/ static int configure_bridge (struct pci_func **func_passed, u8 slotno) { @@ -579,11 +571,11 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) u16 pfmem_base; u32 bar[2]; u32 len[2]; - u8 flag_io = FALSE; - u8 flag_mem = FALSE; - u8 flag_pfmem = FALSE; - u8 need_io_upper = FALSE; - u8 need_pfmem_upper = FALSE; + u8 flag_io = 0; + u8 flag_mem = 0; + u8 flag_pfmem = 0; + u8 need_io_upper = 0; + u8 need_pfmem_upper = 0; struct res_needed *amount_needed = NULL; struct resource_node *io = NULL; struct resource_node *bus_io[2] = {NULL, NULL}; @@ -603,7 +595,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) u8 irq; int retval; - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); devfn = PCI_DEVFN(func->function, func->device); ibmphp_pci_bus->number = func->busno; @@ -630,7 +622,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number); - + /* __________________For debugging purposes only __________________________________ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug ("sec_number after write/read is %x\n", sec_number); @@ -652,7 +644,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ @@ -677,14 +669,13 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) debug ("len[count] in IO = %x\n", len[count]); - bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - + bus_io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); + if (!bus_io[count]) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (bus_io[count], 0, sizeof (struct resource_node)); bus_io[count]->type = IO; bus_io[count]->busno = func->busno; bus_io[count]->devfunc = PCI_DEVFN(func->device, @@ -711,42 +702,40 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) debug ("len[count] in PFMEM = %x\n", len[count]); - bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + bus_pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!bus_pfmem[count]) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (bus_pfmem[count], 0, sizeof (struct resource_node)); bus_pfmem[count]->type = PFMEM; bus_pfmem[count]->busno = func->busno; bus_pfmem[count]->devfunc = PCI_DEVFN(func->device, func->function); bus_pfmem[count]->len = len[count]; - bus_pfmem[count]->fromMem = FALSE; + bus_pfmem[count]->fromMem = 0; if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { ibmphp_add_resource (bus_pfmem[count]); func->pfmem[count] = bus_pfmem[count]; } else { - mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL); + mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL); if (!mem_tmp) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (mem_tmp, 0, sizeof (struct resource_node)); mem_tmp->type = MEM; mem_tmp->busno = bus_pfmem[count]->busno; mem_tmp->devfunc = bus_pfmem[count]->devfunc; mem_tmp->len = bus_pfmem[count]->len; if (ibmphp_check_resource (mem_tmp, 0) == 0) { ibmphp_add_resource (mem_tmp); - bus_pfmem[count]->fromMem = TRUE; + bus_pfmem[count]->fromMem = 1; bus_pfmem[count]->rangeno = mem_tmp->rangeno; ibmphp_add_pfmem_from_mem (bus_pfmem[count]); func->pfmem[count] = bus_pfmem[count]; } else { - err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", func->busno, func->device, len[count]); kfree (mem_tmp); kfree (bus_pfmem[count]); @@ -770,13 +759,12 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) debug ("len[count] in Memory is %x\n", len[count]); - bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + bus_mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!bus_mem[count]) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (bus_mem[count], 0, sizeof (struct resource_node)); bus_mem[count]->type = MEM; bus_mem[count]->busno = func->busno; bus_mem[count]->devfunc = PCI_DEVFN(func->device, @@ -817,7 +805,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) debug ("amount_needed->mem = %x\n", amount_needed->mem); debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); - if (amount_needed->not_correct) { + if (amount_needed->not_correct) { debug ("amount_needed is not correct\n"); for (count = 0; address[count]; count++) { /* for 2 BARs */ @@ -838,17 +826,16 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) if (!amount_needed->io) { debug ("it doesn't want IO?\n"); - flag_io = TRUE; + flag_io = 1; } else { debug ("it wants %x IO behind the bridge\n", amount_needed->io); - io = kmalloc(sizeof(*io), GFP_KERNEL); - + io = kzalloc(sizeof(*io), GFP_KERNEL); + if (!io) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (io, 0, sizeof (struct resource_node)); io->type = IO; io->busno = func->busno; io->devfunc = PCI_DEVFN(func->device, func->function); @@ -856,71 +843,68 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) if (ibmphp_check_resource (io, 1) == 0) { debug ("were we able to add io\n"); ibmphp_add_resource (io); - flag_io = TRUE; + flag_io = 1; } } if (!amount_needed->mem) { debug ("it doesn't want n.e.memory?\n"); - flag_mem = TRUE; + flag_mem = 1; } else { debug ("it wants %x memory behind the bridge\n", amount_needed->mem); - mem = kmalloc(sizeof(*mem), GFP_KERNEL); + mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (mem, 0, sizeof (struct resource_node)); mem->type = MEM; mem->busno = func->busno; mem->devfunc = PCI_DEVFN(func->device, func->function); mem->len = amount_needed->mem; if (ibmphp_check_resource (mem, 1) == 0) { ibmphp_add_resource (mem); - flag_mem = TRUE; + flag_mem = 1; debug ("were we able to add mem\n"); } } if (!amount_needed->pfmem) { debug ("it doesn't want n.e.pfmem mem?\n"); - flag_pfmem = TRUE; + flag_pfmem = 1; } else { debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); - pfmem = kmalloc(sizeof(*pfmem), GFP_KERNEL); + pfmem = kzalloc(sizeof(*pfmem), GFP_KERNEL); if (!pfmem) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (pfmem, 0, sizeof (struct resource_node)); pfmem->type = PFMEM; pfmem->busno = func->busno; pfmem->devfunc = PCI_DEVFN(func->device, func->function); pfmem->len = amount_needed->pfmem; - pfmem->fromMem = FALSE; + pfmem->fromMem = 0; if (ibmphp_check_resource (pfmem, 1) == 0) { ibmphp_add_resource (pfmem); - flag_pfmem = TRUE; + flag_pfmem = 1; } else { - mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL); + mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL); if (!mem_tmp) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (mem_tmp, 0, sizeof (struct resource_node)); mem_tmp->type = MEM; mem_tmp->busno = pfmem->busno; mem_tmp->devfunc = pfmem->devfunc; mem_tmp->len = pfmem->len; if (ibmphp_check_resource (mem_tmp, 1) == 0) { ibmphp_add_resource (mem_tmp); - pfmem->fromMem = TRUE; + pfmem->fromMem = 1; pfmem->rangeno = mem_tmp->rangeno; ibmphp_add_pfmem_from_mem (pfmem); - flag_pfmem = TRUE; + flag_pfmem = 1; } } } @@ -936,13 +920,12 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) */ bus = ibmphp_find_res_bus (sec_number); if (!bus) { - bus = kmalloc(sizeof(*bus), GFP_KERNEL); + bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (!bus) { err ("out of system memory\n"); retval = -ENOMEM; goto error; } - memset (bus, 0, sizeof (struct bus_node)); bus->busno = sec_number; debug ("b4 adding new bus\n"); rc = add_new_bus (bus, io, mem, pfmem, func->busno); @@ -967,16 +950,16 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { debug ("io 32\n"); - need_io_upper = TRUE; + need_io_upper = 1; } - if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + if ((pfmem_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { debug ("pfmem 64\n"); - need_pfmem_upper = TRUE; + need_pfmem_upper = 1; } if (bus->noIORanges) { pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); /* _______________This is for debugging purposes only ____________________ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp); @@ -997,7 +980,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) if (bus->noMemRanges) { pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); - + /* ____________________This is for debugging purposes only ________________________ pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp); debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); @@ -1034,7 +1017,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno) pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); if ((irq > 0x00) && (irq < 0x05)) pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); - /* + /* pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl); pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); @@ -1088,9 +1071,9 @@ error: * This function adds up the amount of resources needed behind the PPB bridge * and passes it to the configure_bridge function * Input: bridge function - * Ouput: amount of resources needed + * Output: amount of resources needed *****************************************************************************/ -static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +static struct res_needed *scan_behind_bridge (struct pci_func *func, u8 busno) { int count, len[6]; u16 vendor_id; @@ -1111,10 +1094,9 @@ static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) }; struct res_needed *amount; - amount = kmalloc(sizeof(*amount), GFP_KERNEL); + amount = kzalloc(sizeof(*amount), GFP_KERNEL); if (amount == NULL) return NULL; - memset (amount, 0, sizeof (struct res_needed)); ibmphp_pci_bus->number = busno; @@ -1137,20 +1119,18 @@ static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) debug ("hdr_type behind the bridge is %x\n", hdr_type); if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { err ("embedded bridges not supported for hot-plugging.\n"); - amount->not_correct = TRUE; + amount->not_correct = 1; return amount; } class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; + err ("The device %x is VGA compatible and as is not supported for hot plugging. Please choose another device.\n", device); + amount->not_correct = 1; return amount; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; + err ("The device %x is not supported for hot plugging. Please choose another device.\n", device); + amount->not_correct = 1; return amount; } @@ -1210,9 +1190,9 @@ static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) } /* end for */ if (!howmany) - amount->not_correct = TRUE; + amount->not_correct = 1; else - amount->not_correct = FALSE; + amount->not_correct = 0; if ((amount->io) && (amount->io < IOBRIDGE)) amount->io = IOBRIDGE; if ((amount->mem) && (amount->mem < MEMBRIDGE)) @@ -1222,9 +1202,9 @@ static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) return amount; } -/* The following 3 unconfigure_boot_ routines deal with the case when we had the card - * upon bootup in the system, since we don't allocate func to such case, we need to read - * the start addresses from pci config space and then find the corresponding entries in +/* The following 3 unconfigure_boot_ routines deal with the case when we had the card + * upon bootup in the system, since we don't allocate func to such case, we need to read + * the start addresses from pci config space and then find the corresponding entries in * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) * Change: we also call these functions even if we configured the card ourselves (i.e., not * the bootup case), since it should work same way @@ -1252,7 +1232,7 @@ static int unconfigure_boot_device (u8 busno, u8 device, u8 function) u32 tmp_address; unsigned int devfn; - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); bus = ibmphp_find_res_bus (busno); if (!bus) { @@ -1369,7 +1349,7 @@ static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) bus_no = (int) busno; debug ("busno is %x\n", busno); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); - debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); + debug ("%s - busno = %x, primary_number = %x\n", __func__, busno, pri_number); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug ("sec_number is %x\n", sec_number); @@ -1389,12 +1369,12 @@ static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) } bus = ibmphp_find_res_bus (sec_number); - debug ("bus->busno is %x\n", bus->busno); - debug ("sec_number is %x\n", sec_number); if (!bus) { err ("cannot find Bus structure for the bridged device\n"); return -EINVAL; } + debug("bus->busno is %x\n", bus->busno); + debug("sec_number is %x\n", sec_number); ibmphp_remove_bus (bus, busno); @@ -1455,7 +1435,7 @@ static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) } } /* end of mem */ } /* end of for */ - debug ("%s - exiting, returning success\n", __FUNCTION__); + debug ("%s - exiting, returning success\n", __func__); return 0; } @@ -1471,7 +1451,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) unsigned int devfn; u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); device = slot_cur->device; busno = slot_cur->bus; @@ -1488,7 +1468,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) /* found correct device!!! */ ++valid_device; - debug ("%s - found correct device\n", __FUNCTION__); + debug ("%s - found correct device\n", __func__); /* header: x x x x x x x x * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge @@ -1501,12 +1481,10 @@ static int unconfigure_boot_card (struct slot *slot_cur) debug ("hdr_type %x, class %x\n", hdr_type, class); class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x function %x is VGA compatible and is not supported for hot removing. " - "Please choose another device.\n", device, function); + err ("The device %x function %x is VGA compatible and is not supported for hot removing. Please choose another device.\n", device, function); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x function %x is not supported for hot removing. " - "Please choose another device.\n", device, function); + err ("The device %x function %x is not supported for hot removing. Please choose another device.\n", device, function); return -ENODEV; } @@ -1531,9 +1509,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) case PCI_HEADER_TYPE_BRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); + err ("This device %x function %x is not PCI-to-PCI bridge, and is not supported for hot-removing. Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); @@ -1547,9 +1523,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); + err ("This device %x function %x is not PCI-to-PCI bridge, and is not supported for hot-removing. Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); @@ -1579,8 +1553,8 @@ static int unconfigure_boot_card (struct slot *slot_cur) * unconfiguring the device * TO DO: will probably need to add some code in case there was some resource, * to remove it... this is from when we have errors in the configure_card... - * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! - * Returns: 0, -1, -ENODEV + * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! + * Returns: 0, -1, -ENODEV */ int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) { @@ -1591,7 +1565,7 @@ int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) struct pci_func *cur_func = NULL; struct pci_func *temp_func; - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); if (!the_end) { /* Need to unconfigure the card */ @@ -1642,7 +1616,7 @@ int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) sl->func = NULL; *slot_cur = sl; - debug ("%s - exit\n", __FUNCTION__); + debug ("%s - exit\n", __func__); return 0; } @@ -1652,7 +1626,7 @@ int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) * Input: bus and the amount of resources needed (we know we can assign those, * since they've been checked already * Output: bus added to the correct spot - * 0, -1, error + * 0, -1, error */ static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) { @@ -1668,16 +1642,15 @@ static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct r err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); return -ENODEV; } - + list_add (&bus->bus_list, &cur_bus->bus_list); } if (io) { - io_range = kmalloc(sizeof(*io_range), GFP_KERNEL); + io_range = kzalloc(sizeof(*io_range), GFP_KERNEL); if (!io_range) { err ("out of system memory\n"); return -ENOMEM; } - memset (io_range, 0, sizeof (struct range_node)); io_range->start = io->start; io_range->end = io->end; io_range->rangeno = 1; @@ -1685,12 +1658,11 @@ static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct r bus->rangeIO = io_range; } if (mem) { - mem_range = kmalloc(sizeof(*mem_range), GFP_KERNEL); + mem_range = kzalloc(sizeof(*mem_range), GFP_KERNEL); if (!mem_range) { err ("out of system memory\n"); return -ENOMEM; } - memset (mem_range, 0, sizeof (struct range_node)); mem_range->start = mem->start; mem_range->end = mem->end; mem_range->rangeno = 1; @@ -1698,12 +1670,11 @@ static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct r bus->rangeMem = mem_range; } if (pfmem) { - pfmem_range = kmalloc(sizeof(*pfmem_range), GFP_KERNEL); - if (!pfmem_range) { + pfmem_range = kzalloc(sizeof(*pfmem_range), GFP_KERNEL); + if (!pfmem_range) { err ("out of system memory\n"); return -ENOMEM; } - memset (pfmem_range, 0, sizeof (struct range_node)); pfmem_range->start = pfmem->start; pfmem_range->end = pfmem->end; pfmem_range->rangeno = 1; @@ -1747,4 +1718,3 @@ static u8 find_sec_number (u8 primary_busno, u8 slotno) return busno; return 0xff; } - diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c index 9c224c94d69..f34745abd5b 100644 --- a/drivers/pci/hotplug/ibmphp_res.c +++ b/drivers/pci/hotplug/ibmphp_res.c @@ -40,28 +40,27 @@ static void update_resources (struct bus_node *bus_cur, int type, int rangeno); static int once_over (void); static int remove_ranges (struct bus_node *, struct bus_node *); static int update_bridge_ranges (struct bus_node **); -static int add_range (int type, struct range_node *, struct bus_node *); +static int add_bus_range (int type, struct range_node *, struct bus_node *); static void fix_resources (struct bus_node *); static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); static LIST_HEAD(gbuses); -static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) +static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc *curr, u8 busno, int flag) { - struct bus_node * newbus; + struct bus_node *newbus; if (!(curr) && !(flag)) { err ("NULL pointer passed\n"); return NULL; } - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL); if (!newbus) { err ("out of system memory\n"); return NULL; } - memset (newbus, 0, sizeof (struct bus_node)); if (flag) newbus->busno = busno; else @@ -70,21 +69,20 @@ static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 return newbus; } -static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) +static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc *curr) { struct resource_node *rs; - + if (!curr) { err ("NULL passed to allocate\n"); return NULL; } - rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + rs = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!rs) { err ("out of system memory\n"); return NULL; } - memset (rs, 0, sizeof (struct resource_node)); rs->busno = curr->bus_num; rs->devfunc = curr->dev_fun; rs->start = curr->start_addr; @@ -95,17 +93,16 @@ static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * cur static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) { - struct bus_node * newbus; + struct bus_node *newbus; struct range_node *newrange; u8 num_ranges = 0; if (first_bus) { - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL); if (!newbus) { err ("out of system memory.\n"); return -ENOMEM; } - memset (newbus, 0, sizeof (struct bus_node)); newbus->busno = curr->bus_num; } else { newbus = *new_bus; @@ -122,22 +119,21 @@ static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node } } - newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); + newrange = kzalloc(sizeof(struct range_node), GFP_KERNEL); if (!newrange) { if (first_bus) kfree (newbus); err ("out of system memory\n"); return -ENOMEM; } - memset (newrange, 0, sizeof (struct range_node)); newrange->start = curr->start_addr; newrange->end = curr->end_addr; - + if (first_bus || (!num_ranges)) newrange->rangeno = 1; else { /* need to insert our range */ - add_range (flag, newrange, newbus); + add_bus_range (flag, newrange, newbus); debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); } @@ -166,7 +162,7 @@ static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node newbus->rangePFMem = newrange; if (first_bus) newbus->noPFMemRanges = 1; - else { + else { debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); ++newbus->noPFMemRanges; fix_resources (newbus); @@ -194,7 +190,7 @@ static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node * This is the Resource Management initialization function. It will go through * the Resource list taken from EBDA and fill in this module's data structures * - * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, + * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW * * Input: ptr to the head of the resource list from EBDA @@ -329,7 +325,7 @@ int __init ibmphp_rsrc_init (void) if (!new_pfmem) return -ENOMEM; new_pfmem->type = PFMEM; - new_pfmem->fromMem = FALSE; + new_pfmem->fromMem = 0; if (ibmphp_add_resource (new_pfmem) < 0) { newbus = alloc_error_bus (curr, 0, 0); if (!newbus) @@ -386,9 +382,9 @@ int __init ibmphp_rsrc_init (void) * pci devices' resources for the appropriate resource * * Input: type of the resource, range to add, current bus - * Output: 0 or -1, bus and range ptrs + * Output: 0 or -1, bus and range ptrs ********************************************************************************/ -static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +static int add_bus_range (int type, struct range_node *range, struct bus_node *bus_cur) { struct range_node *range_cur = NULL; struct range_node *range_prev; @@ -459,18 +455,18 @@ static int add_range (int type, struct range_node *range, struct bus_node *bus_c /******************************************************************************* * This routine goes through the list of resources of type 'type' and updates - * the range numbers that they correspond to. It was called from add_range fnc + * the range numbers that they correspond to. It was called from add_bus_range fnc * * Input: bus, type of the resource, the rangeno starting from which to update ******************************************************************************/ static void update_resources (struct bus_node *bus_cur, int type, int rangeno) { struct resource_node *res = NULL; - u8 eol = FALSE; /* end of list indicator */ + u8 eol = 0; /* end of list indicator */ switch (type) { case MEM: - if (bus_cur->firstMem) + if (bus_cur->firstMem) res = bus_cur->firstMem; break; case PFMEM: @@ -492,7 +488,7 @@ static void update_resources (struct bus_node *bus_cur, int type, int rangeno) else if (res->nextRange) res = res->nextRange; else { - eol = TRUE; + eol = 1; break; } } @@ -567,7 +563,7 @@ static void fix_resources (struct bus_node *bus_cur) struct range_node *range; struct resource_node *res; - debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); + debug ("%s - bus_cur->busno = %d\n", __func__, bus_cur->busno); if (bus_cur->needIOUpdate) { res = bus_cur->firstIO; @@ -587,7 +583,7 @@ static void fix_resources (struct bus_node *bus_cur) } /******************************************************************************* - * This routine adds a resource to the list of resources to the appropriate bus + * This routine adds a resource to the list of resources to the appropriate bus * based on their resource type and sorted by their starting addresses. It assigns * the ptrs to next and nextRange if needed. * @@ -603,17 +599,17 @@ int ibmphp_add_resource (struct resource_node *res) struct range_node *range_cur = NULL; struct resource_node *res_start = NULL; - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); if (!res) { err ("NULL passed to add\n"); return -ENODEV; } - + bus_cur = find_bus_wprev (res->busno, NULL, 0); - + if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ + /* didn't find a bus, something's wrong!!! */ debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); return -ENODEV; } @@ -652,7 +648,7 @@ int ibmphp_add_resource (struct resource_node *res) if (!range_cur) { switch (res->type) { case IO: - ++bus_cur->needIOUpdate; + ++bus_cur->needIOUpdate; break; case MEM: ++bus_cur->needMemUpdate; @@ -663,13 +659,13 @@ int ibmphp_add_resource (struct resource_node *res) } res->rangeno = -1; } - + debug ("The range is %d\n", res->rangeno); if (!res_start) { /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ switch (res->type) { case IO: - bus_cur->firstIO = res; + bus_cur->firstIO = res; break; case MEM: bus_cur->firstMem = res; @@ -677,7 +673,7 @@ int ibmphp_add_resource (struct resource_node *res) case PFMEM: bus_cur->firstPFMem = res; break; - } + } res->next = NULL; res->nextRange = NULL; } else { @@ -766,7 +762,7 @@ int ibmphp_add_resource (struct resource_node *res) } } - debug ("%s - exit\n", __FUNCTION__); + debug ("%s - exit\n", __func__); return 0; } @@ -774,7 +770,7 @@ int ibmphp_add_resource (struct resource_node *res) * This routine will remove the resource from the list of resources * * Input: io, mem, and/or pfmem resource to be deleted - * Ouput: modified resource list + * Output: modified resource list * 0 or error code ****************************************************************************/ int ibmphp_remove_resource (struct resource_node *res) @@ -793,8 +789,7 @@ int ibmphp_remove_resource (struct resource_node *res) bus_cur = find_bus_wprev (res->busno, NULL, 0); if (!bus_cur) { - err ("cannot find corresponding bus of the io resource to remove " - "bailing out...\n"); + err ("cannot find corresponding bus of the io resource to remove bailing out...\n"); return -ENODEV; } @@ -829,7 +824,7 @@ int ibmphp_remove_resource (struct resource_node *res) if (!res_cur) { if (res->type == PFMEM) { - /* + /* * case where pfmem might be in the PFMemFromMem list * so will also need to remove the corresponding mem * entry @@ -938,9 +933,9 @@ int ibmphp_remove_resource (struct resource_node *res) return 0; } -static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +static struct range_node *find_range (struct bus_node *bus_cur, struct resource_node *res) { - struct range_node * range = NULL; + struct range_node *range = NULL; switch (res->type) { case IO: @@ -965,12 +960,12 @@ static struct range_node * find_range (struct bus_node *bus_cur, struct resource } /***************************************************************************** - * This routine will check to make sure the io/mem/pfmem->len that the device asked for + * This routine will check to make sure the io/mem/pfmem->len that the device asked for * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, * otherwise, returns 0 * * Input: resource - * Ouput: the correct start and end address are inputted into the resource node, + * Output: the correct start and end address are inputted into the resource node, * 0 or -EINVAL *****************************************************************************/ int ibmphp_check_resource (struct resource_node *res, u8 bridge) @@ -983,7 +978,7 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) int noranges = 0; u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ u32 tmp_divide; - u8 flag = FALSE; + u8 flag = 0; if (!res) return -EINVAL; @@ -1000,12 +995,12 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) bus_cur = find_bus_wprev (res->busno, NULL, 0); if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ + /* didn't find a bus, something's wrong!!! */ debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); return -EINVAL; } - debug ("%s - enter\n", __FUNCTION__); + debug ("%s - enter\n", __func__); debug ("bus_cur->busno is %d\n", bus_cur->busno); /* This is a quick fix to not mess up with the code very much. i.e., @@ -1033,7 +1028,7 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) while (res_cur) { range = find_range (bus_cur, res_cur); - debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); + debug ("%s - rangeno = %d\n", __func__, res_cur->rangeno); if (!range) { err ("no range for the device exists... bailing out...\n"); @@ -1050,17 +1045,17 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if ((range->start % tmp_divide) == 0) { /* just perfect, starting address is divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = range->start; } else { /* Needs adjusting */ tmp_start = range->start; - flag = FALSE; + flag = 0; while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1070,7 +1065,7 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) break; } } - + if (flag && len_cur == res->len) { debug ("but we are not here, right?\n"); res->start = start_cur; @@ -1089,17 +1084,17 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if (((res_cur->end + 1) % tmp_divide) == 0) { /* just perfect, starting address is divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = res_cur->end + 1; } else { /* Needs adjusting */ tmp_start = res_cur->end + 1; - flag = FALSE; + flag = 0; while ((len_tmp = range->end - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1122,22 +1117,22 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if (res_prev) { if (res_prev->rangeno != res_cur->rangeno) { /* 1st device on this range */ - if ((res_cur->start != range->start) && + if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { + if ((range->start % tmp_divide) == 0) { /* just perfect, starting address is divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = range->start; } else { /* Needs adjusting */ tmp_start = range->start; - flag = FALSE; + flag = 0; while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1162,17 +1157,17 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if ((len_tmp < len_cur) || (len_cur == 0)) { if (((res_prev->end + 1) % tmp_divide) == 0) { /* just perfect, starting address's divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = res_prev->end + 1; } else { /* Needs adjusting */ tmp_start = res_prev->end + 1; - flag = FALSE; + flag = 0; while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1221,17 +1216,17 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if ((len_tmp < len_cur) || (len_cur == 0)) { if ((range->start % tmp_divide) == 0) { /* just perfect, starting address's divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = range->start; } else { /* Needs adjusting */ tmp_start = range->start; - flag = FALSE; + flag = 0; while ((len_tmp = range->end - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1285,17 +1280,17 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) if ((len_tmp < len_cur) || (len_cur == 0)) { if ((range->start % tmp_divide) == 0) { /* just perfect, starting address's divisible by length */ - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = range->start; } else { /* Needs adjusting */ tmp_start = range->start; - flag = FALSE; + flag = 0; while ((len_tmp = range->end - tmp_start) >= res->len) { if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; + flag = 1; len_cur = len_tmp; start_cur = tmp_start; break; @@ -1348,7 +1343,7 @@ int ibmphp_check_resource (struct resource_node *res, u8 bridge) * This routine is called from remove_card if the card contained PPB. * It will remove all the resources on the bus as well as the bus itself * Input: Bus - * Ouput: 0, -ENODEV + * Output: 0, -ENODEV ********************************************************************************/ int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) { @@ -1357,7 +1352,7 @@ int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) struct bus_node *prev_bus; int rc; - prev_bus = find_bus_wprev (parent_busno, NULL, 0); + prev_bus = find_bus_wprev (parent_busno, NULL, 0); if (!prev_bus) { debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); @@ -1428,7 +1423,7 @@ int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) } /****************************************************************************** - * This routine deletes the ranges from a given bus, and the entries from the + * This routine deletes the ranges from a given bus, and the entries from the * parent's bus in the resources * Input: current bus, previous bus * Output: 0, -EINVAL @@ -1457,7 +1452,7 @@ static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) if (bus_cur->noMemRanges) { range_cur = bus_cur->rangeMem; for (i = 0; i < bus_cur->noMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) return -EINVAL; ibmphp_remove_resource (res); @@ -1471,7 +1466,7 @@ static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) if (bus_cur->noPFMemRanges) { range_cur = bus_cur->rangePFMem; for (i = 0; i < bus_cur->noPFMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) return -EINVAL; ibmphp_remove_resource (res); @@ -1486,7 +1481,7 @@ static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) } /* - * find the resource node in the bus + * find the resource node in the bus * Input: Resource needed, start address of the resource, type of resource */ int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) @@ -1516,7 +1511,7 @@ int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resour err ("wrong type of flag\n"); return -EINVAL; } - + while (res_cur) { if (res_cur->start == start_address) { *res = res_cur; @@ -1688,7 +1683,7 @@ static int __init once_over (void) bus_cur = list_entry (tmp, struct bus_node, bus_list); if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { - pfmem_cur->fromMem = TRUE; + pfmem_cur->fromMem = 1; if (pfmem_prev) pfmem_prev->next = pfmem_cur->next; else @@ -1705,12 +1700,11 @@ static int __init once_over (void) bus_cur->firstPFMemFromMem = pfmem_cur; - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!mem) { err ("out of system memory\n"); return -ENOMEM; } - memset (mem, 0, sizeof (struct resource_node)); mem->type = MEM; mem->busno = pfmem_cur->busno; mem->devfunc = pfmem_cur->devfunc; @@ -1723,7 +1717,7 @@ static int __init once_over (void) } /* end for pfmem */ } /* end if */ } /* end list_for_each bus */ - return 0; + return 0; } int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) @@ -1765,9 +1759,9 @@ static struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u list_for_each (tmp, &gbuses) { tmp_prev = tmp->prev; bus_cur = list_entry (tmp, struct bus_node, bus_list); - if (flag) + if (flag) *prev = list_entry (tmp_prev, struct bus_node, bus_list); - if (bus_cur->busno == bus_number) + if (bus_cur->busno == bus_number) return bus_cur; } @@ -1781,7 +1775,7 @@ void ibmphp_print_test (void) struct range_node *range; struct resource_node *res; struct list_head *tmp; - + debug_pci ("*****************START**********************\n"); if ((!list_empty(&gbuses)) && flags) { @@ -1911,7 +1905,7 @@ static int range_exists_already (struct range_node * range, struct bus_node * bu return 1; range_cur = range_cur->next; } - + return 0; } @@ -1925,7 +1919,7 @@ static int range_exists_already (struct range_node * range, struct bus_node * bu * Returns: none * Note: this function doesn't take into account IO restrictions etc, * so will only work for bridges with no video/ISA devices behind them It - * also will not work for onboard PPB's that can have more than 1 *bus + * also will not work for onboard PPBs that can have more than 1 *bus * behind them All these are TO DO. * Also need to add more error checkings... (from fnc returns etc) */ @@ -1947,7 +1941,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) return -ENODEV; ibmphp_pci_bus->number = bus_cur->busno; - debug ("inside %s\n", __FUNCTION__); + debug ("inside %s\n", __func__); debug ("bus_cur->busno = %x\n", bus_cur->busno); for (device = 0; device < 32; device++) { @@ -1968,7 +1962,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) case PCI_HEADER_TYPE_BRIDGE: function = 0x8; case PCI_HEADER_TYPE_MULTIBRIDGE: - /* We assume here that only 1 bus behind the bridge + /* We assume here that only 1 bus behind the bridge TO DO: add functionality for several: temp = secondary; while (temp < subordinate) { @@ -1977,7 +1971,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) } */ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); - bus_sec = find_bus_wprev (sec_busno, NULL, 0); + bus_sec = find_bus_wprev (sec_busno, NULL, 0); /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ if (!bus_sec) { bus_sec = alloc_error_bus (NULL, sec_busno, 1); @@ -1994,18 +1988,17 @@ static int __init update_bridge_ranges (struct bus_node **bus) end_address |= (upper_io_end << 16); if ((start_address) && (start_address <= end_address)) { - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + range = kzalloc(sizeof(struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } - memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfff; if (bus_sec->noIORanges > 0) { if (!range_exists_already (range, bus_sec, IO)) { - add_range (IO, range, bus_sec); + add_bus_range (IO, range, bus_sec); ++bus_sec->noIORanges; } else { kfree (range); @@ -2020,13 +2013,12 @@ static int __init update_bridge_ranges (struct bus_node **bus) fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { - io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + io = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!io) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } - memset (io, 0, sizeof (struct resource_node)); io->type = IO; io->busno = bus_cur->busno; io->devfunc = ((device << 3) | (function & 0x7)); @@ -2035,7 +2027,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) io->len = io->end - io->start + 1; ibmphp_add_resource (io); } - } + } pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); @@ -2045,18 +2037,17 @@ static int __init update_bridge_ranges (struct bus_node **bus) if ((start_address) && (start_address <= end_address)) { - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + range = kzalloc(sizeof(struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } - memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfffff; if (bus_sec->noMemRanges > 0) { if (!range_exists_already (range, bus_sec, MEM)) { - add_range (MEM, range, bus_sec); + add_bus_range (MEM, range, bus_sec); ++bus_sec->noMemRanges; } else { kfree (range); @@ -2072,13 +2063,12 @@ static int __init update_bridge_ranges (struct bus_node **bus) fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!mem) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } - memset (mem, 0, sizeof (struct resource_node)); mem->type = MEM; mem->busno = bus_cur->busno; mem->devfunc = ((device << 3) | (function & 0x7)); @@ -2101,18 +2091,17 @@ static int __init update_bridge_ranges (struct bus_node **bus) if ((start_address) && (start_address <= end_address)) { - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + range = kzalloc(sizeof(struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } - memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfffff; if (bus_sec->noPFMemRanges > 0) { if (!range_exists_already (range, bus_sec, PFMEM)) { - add_range (PFMEM, range, bus_sec); + add_bus_range (PFMEM, range, bus_sec); ++bus_sec->noPFMemRanges; } else { kfree (range); @@ -2127,20 +2116,19 @@ static int __init update_bridge_ranges (struct bus_node **bus) fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { - pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + pfmem = kzalloc(sizeof(struct resource_node), GFP_KERNEL); if (!pfmem) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } - memset (pfmem, 0, sizeof (struct resource_node)); pfmem->type = PFMEM; pfmem->busno = bus_cur->busno; pfmem->devfunc = ((device << 3) | (function & 0x7)); pfmem->start = start_address; pfmem->end = end_address + 0xfffff; pfmem->len = pfmem->end - pfmem->start + 1; - pfmem->fromMem = FALSE; + pfmem->fromMem = 0; ibmphp_add_resource (pfmem); } diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h deleted file mode 100644 index 88d44f7fef2..00000000000 --- a/drivers/pci/hotplug/pci_hotplug.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com> - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_ECC = 0x05, - PCI_SPEED_100MHz_PCIX_ECC = 0x06, - PCI_SPEED_133MHz_PCIX_ECC = 0x07, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0x12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -/* These values come from the PCI Express Spec */ -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0x00, - PCIE_LNK_X1 = 0x01, - PCIE_LNK_X2 = 0x02, - PCIE_LNK_X4 = 0x04, - PCIE_LNK_X8 = 0x08, - PCIE_LNK_X12 = 0x0C, - PCIE_LNK_X16 = 0x10, - PCIE_LNK_X32 = 0x20, - PCIE_LNK_WIDTH_UNKNOWN = 0xFF, -}; - -enum pcie_link_speed { - PCIE_2PT5GB = 0x14, - PCIE_LNK_SPEED_UNKNOWN = 0xFF, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); - -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_address: Called to get pci address of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_address) (struct hotplug_slot *slot, u32 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * @address: (domain << 16 | bus << 8 | dev) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - u32 address; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the initial values for - * this slot. - * @release: called during pci_hp_deregister to free memory allocated in a - * hotplug_slot structure. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void (*release) (struct hotplug_slot *slot); - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; -#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); -extern struct subsystem pci_hotplug_slots_subsys; - -#endif - diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index c4282902cb5..56d8486dc16 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -21,134 +21,60 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to <greg@kroah.com> - * - * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * Send feedback to <kristen.c.accardi@intel.com> * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/list.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> #include <linux/pagemap.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/mount.h> #include <linux/namei.h> +#include <linux/mutex.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <asm/uaccess.h> -#include <linux/kobject.h> -#include <linux/sysfs.h> -#include "pci_hotplug.h" - +#include "../pci.h" +#include "cpci_hotplug.h" #define MY_NAME "pci_hotplug" -#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## 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) /* local variables */ -static int debug; +static bool debug; #define DRIVER_VERSION "0.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" #define DRIVER_DESC "PCI Hot Plug PCI Core" -////////////////////////////////////////////////////////////////// - static LIST_HEAD(pci_hotplug_slot_list); - -struct subsystem pci_hotplug_slots_subsys; - -static ssize_t hotplug_slot_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct hotplug_slot *slot = to_hotplug_slot(kobj); - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); - return attribute->show ? attribute->show(slot, buf) : -EIO; -} - -static ssize_t hotplug_slot_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) -{ - struct hotplug_slot *slot = to_hotplug_slot(kobj); - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); - return attribute->store ? attribute->store(slot, buf, len) : -EIO; -} - -static struct sysfs_ops hotplug_slot_sysfs_ops = { - .show = hotplug_slot_attr_show, - .store = hotplug_slot_attr_store, -}; - -static void hotplug_slot_release(struct kobject *kobj) -{ - struct hotplug_slot *slot = to_hotplug_slot(kobj); - if (slot->release) - slot->release(slot); -} - -static struct kobj_type hotplug_slot_ktype = { - .sysfs_ops = &hotplug_slot_sysfs_ops, - .release = &hotplug_slot_release, -}; - -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL); - -/* these strings match up with the values in pci_bus_speed */ -static char *pci_bus_speed_strings[] = { - "33 MHz PCI", /* 0x00 */ - "66 MHz PCI", /* 0x01 */ - "66 MHz PCIX", /* 0x02 */ - "100 MHz PCIX", /* 0x03 */ - "133 MHz PCIX", /* 0x04 */ - NULL, /* 0x05 */ - NULL, /* 0x06 */ - NULL, /* 0x07 */ - NULL, /* 0x08 */ - "66 MHz PCIX 266", /* 0x09 */ - "100 MHz PCIX 266", /* 0x0a */ - "133 MHz PCIX 266", /* 0x0b */ - NULL, /* 0x0c */ - NULL, /* 0x0d */ - NULL, /* 0x0e */ - NULL, /* 0x0f */ - NULL, /* 0x10 */ - "66 MHz PCIX 533", /* 0x11 */ - "100 MHz PCIX 533", /* 0x12 */ - "133 MHz PCIX 533", /* 0x13 */ - "25 GBps PCI-E", /* 0x14 */ -}; - -#ifdef CONFIG_HOTPLUG_PCI_CPCI -extern int cpci_hotplug_init(int debug); -extern void cpci_hotplug_exit(void); -#else -static inline int cpci_hotplug_init(int debug) { return 0; } -static inline void cpci_hotplug_exit(void) { } -#endif +static DEFINE_MUTEX(pci_hp_mutex); /* Weee, fun with macros... */ -#define GET_STATUS(name,type) \ -static int get_##name (struct hotplug_slot *slot, type *value) \ +#define GET_STATUS(name, type) \ +static int get_##name(struct hotplug_slot *slot, type *value) \ { \ struct hotplug_slot_ops *ops = slot->ops; \ int retval = 0; \ - if (try_module_get(ops->owner)) { \ - if (ops->get_##name) \ - retval = ops->get_##name (slot, value); \ - else \ - *value = slot->info->name; \ - module_put(ops->owner); \ - } \ + if (!try_module_get(ops->owner)) \ + return -ENODEV; \ + if (ops->get_##name) \ + retval = ops->get_##name(slot, value); \ + else \ + *value = slot->info->name; \ + module_put(ops->owner); \ return retval; \ } @@ -156,236 +82,153 @@ GET_STATUS(power_status, u8) GET_STATUS(attention_status, u8) GET_STATUS(latch_status, u8) GET_STATUS(adapter_status, u8) -GET_STATUS(address, u32) -GET_STATUS(max_bus_speed, enum pci_bus_speed) -GET_STATUS(cur_bus_speed, enum pci_bus_speed) -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) +static ssize_t power_read_file(struct pci_slot *slot, char *buf) { int retval; u8 value; - retval = get_power_status (slot, &value); + retval = get_power_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); -exit: - return retval; + return retval; + + return sprintf(buf, "%d\n", value); } -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) +static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, + size_t count) { + struct hotplug_slot *slot = pci_slot->hotplug; unsigned long lpower; u8 power; int retval = 0; - lpower = simple_strtoul (buf, NULL, 10); + lpower = simple_strtoul(buf, NULL, 10); power = (u8)(lpower & 0xff); - dbg ("power = %d\n", power); + dbg("power = %d\n", power); if (!try_module_get(slot->ops->owner)) { retval = -ENODEV; goto exit; } switch (power) { - case 0: - if (slot->ops->disable_slot) - retval = slot->ops->disable_slot(slot); - break; - - case 1: - if (slot->ops->enable_slot) - retval = slot->ops->enable_slot(slot); - break; - - default: - err ("Illegal value specified for power\n"); - retval = -EINVAL; + case 0: + if (slot->ops->disable_slot) + retval = slot->ops->disable_slot(slot); + break; + + case 1: + if (slot->ops->enable_slot) + retval = slot->ops->enable_slot(slot); + break; + + default: + err("Illegal value specified for power\n"); + retval = -EINVAL; } module_put(slot->ops->owner); -exit: +exit: if (retval) return retval; return count; } -static struct hotplug_slot_attribute hotplug_slot_attr_power = { +static struct pci_slot_attribute hotplug_slot_attr_power = { .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .show = power_read_file, .store = power_write_file }; -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) +static ssize_t attention_read_file(struct pci_slot *slot, char *buf) { int retval; u8 value; - retval = get_attention_status (slot, &value); + retval = get_attention_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) +static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, + size_t count) { + struct hotplug_slot_ops *ops = slot->hotplug->ops; unsigned long lattention; u8 attention; int retval = 0; - lattention = simple_strtoul (buf, NULL, 10); + lattention = simple_strtoul(buf, NULL, 10); attention = (u8)(lattention & 0xff); - dbg (" - attention = %d\n", attention); + dbg(" - attention = %d\n", attention); - if (!try_module_get(slot->ops->owner)) { + if (!try_module_get(ops->owner)) { retval = -ENODEV; goto exit; } - if (slot->ops->set_attention_status) - retval = slot->ops->set_attention_status(slot, attention); - module_put(slot->ops->owner); + if (ops->set_attention_status) + retval = ops->set_attention_status(slot->hotplug, attention); + module_put(ops->owner); -exit: +exit: if (retval) return retval; return count; } -static struct hotplug_slot_attribute hotplug_slot_attr_attention = { +static struct pci_slot_attribute hotplug_slot_attr_attention = { .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .show = attention_read_file, .store = attention_write_file }; -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) +static ssize_t latch_read_file(struct pci_slot *slot, char *buf) { int retval; u8 value; - retval = get_latch_status (slot, &value); + retval = get_latch_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } -static struct hotplug_slot_attribute hotplug_slot_attr_latch = { +static struct pci_slot_attribute hotplug_slot_attr_latch = { .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, .show = latch_read_file, }; -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) +static ssize_t presence_read_file(struct pci_slot *slot, char *buf) { int retval; u8 value; - retval = get_adapter_status (slot, &value); + retval = get_adapter_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } -static struct hotplug_slot_attribute hotplug_slot_attr_presence = { +static struct pci_slot_attribute hotplug_slot_attr_presence = { .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, .show = presence_read_file, }; -static ssize_t address_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u32 address; - - retval = get_address (slot, &address); - if (retval) - goto exit; - retval = sprintf (buf, "%04x:%02x:%02x\n", - (address >> 16) & 0xffff, - (address >> 8) & 0xff, - address & 0xff); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_address = { - .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, - .show = address_read_file, -}; - -static char *unknown_speed = "Unknown bus speed"; - -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_max_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { - .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, - .show = max_bus_speed_read_file, -}; - -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_cur_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { - .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, - .show = cur_bus_speed_read_file, -}; - -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) +static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, + size_t count) { + struct hotplug_slot *slot = pci_slot->hotplug; unsigned long ltest; u32 test; int retval = 0; ltest = simple_strtoul (buf, NULL, 10); test = (u32)(ltest & 0xffffffff); - dbg ("test = %d\n", test); + dbg("test = %d\n", test); if (!try_module_get(slot->ops->owner)) { retval = -ENODEV; @@ -395,309 +238,311 @@ static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, retval = slot->ops->hardware_test(slot, test); module_put(slot->ops->owner); -exit: +exit: if (retval) return retval; return count; } -static struct hotplug_slot_attribute hotplug_slot_attr_test = { +static struct pci_slot_attribute hotplug_slot_attr_test = { .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .store = test_write_file }; -static int has_power_file (struct hotplug_slot *slot) +static bool has_power_file(struct pci_slot *pci_slot) { + struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->enable_slot) || (slot->ops->disable_slot) || (slot->ops->get_power_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_attention_file (struct hotplug_slot *slot) +static bool has_attention_file(struct pci_slot *pci_slot) { + struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->set_attention_status) || (slot->ops->get_attention_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_latch_file (struct hotplug_slot *slot) +static bool has_latch_file(struct pci_slot *pci_slot) { - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_latch_status) - return 0; - return -ENOENT; -} + struct hotplug_slot *slot = pci_slot->hotplug; -static int has_adapter_file (struct hotplug_slot *slot) -{ if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_adapter_status) - return 0; - return -ENOENT; + return false; + if (slot->ops->get_latch_status) + return true; + return false; } -static int has_address_file (struct hotplug_slot *slot) +static bool has_adapter_file(struct pci_slot *pci_slot) { - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_address) - return 0; - return -ENOENT; -} + struct hotplug_slot *slot = pci_slot->hotplug; -static int has_max_bus_speed_file (struct hotplug_slot *slot) -{ if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_max_bus_speed) - return 0; - return -ENOENT; + return false; + if (slot->ops->get_adapter_status) + return true; + return false; } -static int has_cur_bus_speed_file (struct hotplug_slot *slot) +static bool has_test_file(struct pci_slot *pci_slot) { - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_cur_bus_speed) - return 0; - return -ENOENT; -} + struct hotplug_slot *slot = pci_slot->hotplug; -static int has_test_file (struct hotplug_slot *slot) -{ if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->hardware_test) - return 0; - return -ENOENT; + return true; + return false; } -static int fs_add_slot (struct hotplug_slot *slot) +static int fs_add_slot(struct pci_slot *slot) { - if (has_power_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); + int retval = 0; - if (has_attention_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + /* Create symbolic link to the hotplug driver module */ + pci_hp_create_module_link(slot); - if (has_latch_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + if (has_power_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_power.attr); + if (retval) + goto exit_power; + } - if (has_adapter_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + if (has_attention_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); + if (retval) + goto exit_attention; + } - if (has_address_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr); + if (has_latch_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_latch.attr); + if (retval) + goto exit_latch; + } - if (has_max_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + if (has_adapter_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); + if (retval) + goto exit_adapter; + } - if (has_cur_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + if (has_test_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_test.attr); + if (retval) + goto exit_test; + } - if (has_test_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); + goto exit; - return 0; +exit_test: + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); +exit_adapter: + if (has_latch_file(slot)) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); +exit_latch: + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); +exit_attention: + if (has_power_file(slot)) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); +exit_power: + pci_hp_remove_module_link(slot); +exit: + return retval; } -static void fs_remove_slot (struct hotplug_slot *slot) +static void fs_remove_slot(struct pci_slot *slot) { - if (has_power_file(slot) == 0) + if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); - if (has_latch_file(slot) == 0) + if (has_latch_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if (has_address_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); - - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); - if (has_test_file(slot) == 0) + if (has_test_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); + + pci_hp_remove_module_link(slot); } -static struct hotplug_slot *get_slot_from_name (const char *name) +static struct hotplug_slot *get_slot_from_name(const char *name) { struct hotplug_slot *slot; struct list_head *tmp; - list_for_each (tmp, &pci_hotplug_slot_list) { - slot = list_entry (tmp, struct hotplug_slot, slot_list); - if (strcmp(slot->name, name) == 0) + list_for_each(tmp, &pci_hotplug_slot_list) { + slot = list_entry(tmp, struct hotplug_slot, slot_list); + if (strcmp(hotplug_slot_name(slot), name) == 0) return slot; } return NULL; } /** - * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register + * @devnr: device number + * @name: name registered with kobject core + * @owner: caller module owner + * @mod_name: caller module name * * Registers a hotplug slot with the pci hotplug subsystem, which will allow * userspace interaction to the slot. * * Returns 0 if successful, anything else for an error. */ -int pci_hp_register (struct hotplug_slot *slot) +int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, + int devnr, const char *name, + struct module *owner, const char *mod_name) { int result; + struct pci_slot *pci_slot; if (slot == NULL) return -ENODEV; if ((slot->info == NULL) || (slot->ops == NULL)) return -EINVAL; if (slot->release == NULL) { - dbg("Why are you trying to register a hotplug slot" - "without a proper release function?\n"); + dbg("Why are you trying to register a hotplug slot without a proper release function?\n"); return -EINVAL; } - kobject_set_name(&slot->kobj, "%s", slot->name); - kobj_set_kset_s(slot, pci_hotplug_slots_subsys); + slot->ops->owner = owner; + slot->ops->mod_name = mod_name; - /* this can fail if we have already registered a slot with the same name */ - if (kobject_register(&slot->kobj)) { - err("Unable to register kobject"); - return -EINVAL; + mutex_lock(&pci_hp_mutex); + /* + * No problems if we call this interface from both ACPI_PCI_SLOT + * driver and call it here again. If we've already created the + * pci_slot, the interface will simply bump the refcount. + */ + pci_slot = pci_create_slot(bus, devnr, name, slot); + if (IS_ERR(pci_slot)) { + result = PTR_ERR(pci_slot); + goto out; } - - list_add (&slot->slot_list, &pci_hotplug_slot_list); - result = fs_add_slot (slot); - dbg ("Added slot %s to the list\n", slot->name); + slot->pci_slot = pci_slot; + pci_slot->hotplug = slot; + + list_add(&slot->slot_list, &pci_hotplug_slot_list); + + result = fs_add_slot(pci_slot); + kobject_uevent(&pci_slot->kobj, KOBJ_ADD); + dbg("Added slot %s to the list\n", name); +out: + mutex_unlock(&pci_hp_mutex); return result; } +EXPORT_SYMBOL_GPL(__pci_hp_register); /** * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem - * @slot: pointer to the &struct hotplug_slot to deregister + * @hotplug: pointer to the &struct hotplug_slot to deregister * * The @slot must have been registered with the pci hotplug subsystem * previously with a call to pci_hp_register(). * * Returns 0 if successful, anything else for an error. */ -int pci_hp_deregister (struct hotplug_slot *slot) +int pci_hp_deregister(struct hotplug_slot *hotplug) { struct hotplug_slot *temp; + struct pci_slot *slot; - if (slot == NULL) + if (!hotplug) return -ENODEV; - temp = get_slot_from_name (slot->name); - if (temp != slot) { + mutex_lock(&pci_hp_mutex); + temp = get_slot_from_name(hotplug_slot_name(hotplug)); + if (temp != hotplug) { + mutex_unlock(&pci_hp_mutex); return -ENODEV; } - list_del (&slot->slot_list); - fs_remove_slot (slot); - dbg ("Removed slot %s from the list\n", slot->name); - kobject_unregister(&slot->kobj); + list_del(&hotplug->slot_list); + + slot = hotplug->pci_slot; + fs_remove_slot(slot); + dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug)); + + hotplug->release(hotplug); + slot->hotplug = NULL; + pci_destroy_slot(slot); + mutex_unlock(&pci_hp_mutex); + return 0; } +EXPORT_SYMBOL_GPL(pci_hp_deregister); /** * pci_hp_change_slot_info - changes the slot's information structure in the core - * @slot: pointer to the slot whose info has changed + * @hotplug: pointer to the slot whose info has changed * @info: pointer to the info copy into the slot's info structure * - * @slot must have been registered with the pci + * @slot must have been registered with the pci * hotplug subsystem previously with a call to pci_hp_register(). * * Returns 0 if successful, anything else for an error. */ -int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) +int pci_hp_change_slot_info(struct hotplug_slot *hotplug, + struct hotplug_slot_info *info) { - if ((slot == NULL) || (info == NULL)) + if (!hotplug || !info) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr); - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); + memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info)); return 0; } +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); -static int __init pci_hotplug_init (void) +static int __init pci_hotplug_init(void) { int result; - kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); - result = subsystem_register(&pci_hotplug_slots_subsys); - if (result) { - err("Register subsys with error %d\n", result); - goto exit; - } result = cpci_hotplug_init(debug); if (result) { - err ("cpci_hotplug_init with error %d\n", result); - goto err_subsys; + err("cpci_hotplug_init with error %d\n", result); + return result; } - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - goto exit; - -err_subsys: - subsystem_unregister(&pci_hotplug_slots_subsys); -exit: + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); return result; } -static void __exit pci_hotplug_exit (void) +static void __exit pci_hotplug_exit(void) { cpci_hotplug_exit(); - subsystem_unregister(&pci_hotplug_slots_subsys); } module_init(pci_hotplug_init); @@ -708,8 +553,3 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys); -EXPORT_SYMBOL_GPL(pci_hp_register); -EXPORT_SYMBOL_GPL(pci_hp_deregister); -EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 061ead21ef1..8e9012dca45 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -31,120 +31,73 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/delay.h> -#include <asm/semaphore.h> -#include <asm/io.h> +#include <linux/sched.h> /* signal_pending() */ #include <linux/pcieport_if.h> -#include "pci_hotplug.h" +#include <linux/mutex.h> +#include <linux/workqueue.h> #define MY_NAME "pciehp" -extern int pciehp_poll_mode; +extern bool pciehp_poll_mode; extern int pciehp_poll_time; -extern int pciehp_debug; - -/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ -#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## 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) - -struct pci_func { - struct pci_func *next; - u8 bus; - u8 device; - u8 function; - u8 is_a_board; - u16 status; - u8 configured; - u8 switch_save; - u8 presence_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; - u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct pci_dev* pci_dev; -}; +extern bool pciehp_debug; + +#define dbg(format, arg...) \ +do { \ + if (pciehp_debug) \ + printk(KERN_DEBUG "%s: " format, MY_NAME , ## 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 ctrl_dbg(ctrl, format, arg...) \ + do { \ + if (pciehp_debug) \ + dev_printk(KERN_DEBUG, &ctrl->pcie->device, \ + format, ## arg); \ + } while (0) +#define ctrl_err(ctrl, format, arg...) \ + dev_err(&ctrl->pcie->device, format, ## arg) +#define ctrl_info(ctrl, format, arg...) \ + dev_info(&ctrl->pcie->device, format, ## arg) +#define ctrl_warn(ctrl, format, arg...) \ + dev_warn(&ctrl->pcie->device, format, ## arg) +#define SLOT_NAME_SIZE 10 struct slot { - struct slot *next; - u8 bus; - u8 device; - u32 number; - u8 is_a_board; - u8 configured; u8 state; - u8 switch_save; - u8 presence_save; - u32 capabilities; - u16 reserved2; - struct timer_list task_event; - u8 hp_slot; struct controller *ctrl; - struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; - struct list_head slot_list; -}; - -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; + struct delayed_work work; /* work for button event */ + struct mutex lock; + struct mutex hotplug_lock; + struct workqueue_struct *wq; }; struct event_info { u32 event_type; - u8 hp_slot; + struct slot *p_slot; + struct work_struct work; }; struct controller { - struct controller *next; - struct semaphore crit_sect; /* critical section semaphore */ - void *hpc_ctlr_handle; /* HPC controller handle */ - int num_slots; /* Number of slots on ctlr */ - int slot_num_inc; /* 1 or -1 */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct pci_dev *pci_dev; - struct pci_bus *pci_bus; - struct event_info event_queue[10]; + struct mutex ctrl_lock; /* controller lock */ + struct pcie_device *pcie; /* PCI Express port service */ struct slot *slot; - struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ - u8 next_event; - u8 seg; - u8 bus; - u8 device; - u8 function; - u8 rev; - u8 slot_device_offset; - u8 add_support; - enum pci_bus_speed speed; - u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ - u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 ctrlcap; - u16 vendor_id; - u8 cap_base; -}; - -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; -}; - -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; + u32 slot_cap; + struct timer_list poll_timer; + unsigned int cmd_busy:1; + unsigned int no_cmd_complete:1; + unsigned int link_active_reporting:1; + unsigned int notification_enabled:1; + unsigned int power_fault_detected; }; #define INT_BUTTON_IGNORE 0 @@ -157,6 +110,8 @@ struct resource_lists { #define INT_BUTTON_PRESS 7 #define INT_BUTTON_RELEASE 8 #define INT_BUTTON_CANCEL 9 +#define INT_LINK_UP 10 +#define INT_LINK_DOWN 11 #define STATIC_STATE 0 #define BLINKINGON_STATE 1 @@ -164,190 +119,68 @@ struct resource_lists { #define POWERON_STATE 3 #define POWEROFF_STATE 4 -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - -/* Error messages */ -#define INTERLOCK_OPEN 0x00000002 -#define ADD_NOT_SUPPORTED 0x00000003 -#define CARD_FUNCTIONING 0x00000005 -#define ADAPTER_NOT_SAME 0x00000006 -#define NO_ADAPTER_PRESENT 0x00000009 -#define NOT_ENOUGH_RESOURCES 0x0000000B -#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C -#define WRONG_BUS_FREQUENCY 0x0000000D -#define POWER_FAILURE 0x0000000E - -#define REMOVE_NOT_SUPPORTED 0x00000003 - -#define DISABLE_CARD 1 - -/* Field definitions in Slot Capabilities Register */ -#define ATTN_BUTTN_PRSN 0x00000001 -#define PWR_CTRL_PRSN 0x00000002 -#define MRL_SENS_PRSN 0x00000004 -#define ATTN_LED_PRSN 0x00000008 -#define PWR_LED_PRSN 0x00000010 -#define HP_SUPR_RM_SUP 0x00000020 - -#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) -#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) -#define MRL_SENS(cap) (cap & MRL_SENS_PRSN) -#define ATTN_LED(cap) (cap & ATTN_LED_PRSN) -#define PWR_LED(cap) (cap & PWR_LED_PRSN) -#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) - -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" -#define msg_HPC_non_pcie "The PCI hot plug controller is not supported by this driver.\n" -#define msg_HPC_not_supported "This system is not supported by this version of pciephd module. Upgrade to a newer version of pciehpd\n" -#define msg_unable_to_save "Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\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_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" - -/* controller functions */ -extern int pciehprm_find_available_resources (struct controller *ctrl); -extern int pciehp_event_start_thread (void); -extern void pciehp_event_stop_thread (void); -extern struct pci_func *pciehp_slot_create (unsigned char busnumber); -extern struct pci_func *pciehp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int pciehp_enable_slot (struct slot *slot); -extern int pciehp_disable_slot (struct slot *slot); - -extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id); -/* extern void long_delay (int delay); */ - -/* resource functions */ -extern int pciehp_resource_sort_and_combine (struct pci_resource **head); - -/* pci functions */ -extern int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -/*extern int pciehp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ -extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int pciehp_save_used_resources (struct controller *ctrl, struct pci_func * func, int flag); -extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern void pciehp_destroy_board_resources (struct pci_func * func); -extern int pciehp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void pciehp_destroy_resource_list (struct resource_lists * resources); -extern int pciehp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int pciehp_unconfigure_device (struct pci_func* func); - - -/* Global variables */ -extern struct controller *pciehp_ctrl_list; -extern struct pci_func *pciehp_slot_list[256]; - -/* Inline functions */ - -static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) +#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_ABP) +#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_PCP) +#define MRL_SENS(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_MRLSP) +#define ATTN_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_AIP) +#define PWR_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_PIP) +#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_HPS) +#define EMI(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_EIP) +#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS) +#define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) + +int pciehp_sysfs_enable_slot(struct slot *slot); +int pciehp_sysfs_disable_slot(struct slot *slot); +u8 pciehp_handle_attention_button(struct slot *p_slot); +u8 pciehp_handle_switch_change(struct slot *p_slot); +u8 pciehp_handle_presence_change(struct slot *p_slot); +u8 pciehp_handle_power_fault(struct slot *p_slot); +void pciehp_handle_linkstate_change(struct slot *p_slot); +int pciehp_configure_device(struct slot *p_slot); +int pciehp_unconfigure_device(struct slot *p_slot); +void pciehp_queue_pushbutton_work(struct work_struct *work); +struct controller *pcie_init(struct pcie_device *dev); +int pcie_init_notification(struct controller *ctrl); +int pciehp_enable_slot(struct slot *p_slot); +int pciehp_disable_slot(struct slot *p_slot); +void pcie_enable_notification(struct controller *ctrl); +int pciehp_power_on_slot(struct slot *slot); +void pciehp_power_off_slot(struct slot *slot); +void pciehp_get_power_status(struct slot *slot, u8 *status); +void pciehp_get_attention_status(struct slot *slot, u8 *status); + +void pciehp_set_attention_status(struct slot *slot, u8 status); +void pciehp_get_latch_status(struct slot *slot, u8 *status); +void pciehp_get_adapter_status(struct slot *slot, u8 *status); +int pciehp_query_power_fault(struct slot *slot); +void pciehp_green_led_on(struct slot *slot); +void pciehp_green_led_off(struct slot *slot); +void pciehp_green_led_blink(struct slot *slot); +int pciehp_check_link_status(struct controller *ctrl); +bool pciehp_check_link_active(struct controller *ctrl); +void pciehp_release_ctrl(struct controller *ctrl); +int pciehp_reset_slot(struct slot *slot, int probe); + +static inline const char *slot_name(struct slot *slot) { - struct slot *p_slot, *tmp_slot = NULL; - - p_slot = ctrl->slot; - - dbg("p_slot = %p\n", p_slot); - - while (p_slot && (p_slot->device != device)) { - tmp_slot = p_slot; - p_slot = p_slot->next; - dbg("In while loop, p_slot = %p\n", p_slot); - } - if (p_slot == NULL) { - err("ERROR: pciehp_find_slot device=0x%x\n", device); - p_slot = tmp_slot; - } - - return p_slot; + return hotplug_slot_name(slot->hotplug_slot); } -static inline int wait_for_ctrl_irq(struct controller *ctrl) -{ - int retval = 0; - - DECLARE_WAITQUEUE(wait, current); - - dbg("%s : start\n", __FUNCTION__); - add_wait_queue(&ctrl->queue, &wait); - if (!pciehp_poll_mode) - /* Sleep for up to 1 second */ - msleep_interruptible(1000); - else - msleep_interruptible(2500); - - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; +#ifdef CONFIG_ACPI +#include <linux/pci-acpi.h> - dbg("%s : end\n", __FUNCTION__); - return retval; -} +void __init pciehp_acpi_slot_detection_init(void); +int pciehp_acpi_slot_detection_check(struct pci_dev *dev); -/* Puts node back in the resource list pointed to by head */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) +static inline void pciehp_firmware_init(void) { - if (!node || !head) - return; - node->next = *head; - *head = node; + pciehp_acpi_slot_detection_init(); } - -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) +#else +#define pciehp_firmware_init() do {} while (0) +static inline int pciehp_acpi_slot_detection_check(struct pci_dev *dev) { - snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number); + return 0; } - -enum php_ctlr_type { - PCI, - ISA, - ACPI -}; - -typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); - -int pcie_init(struct controller *ctrl, struct pcie_device *dev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback); - - -/* This has no meaning for PCI Express, as there is only 1 slot per port */ -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, - int *first_device_num, - int *physical_slot_num, - u8 *ctrlcap); - -struct hpc_ops { - int (*power_on_slot) (struct slot *slot); - int (*power_off_slot) (struct slot *slot); - int (*get_power_status) (struct slot *slot, u8 *status); - int (*get_attention_status) (struct slot *slot, u8 *status); - int (*set_attention_status) (struct slot *slot, u8 status); - int (*get_latch_status) (struct slot *slot, u8 *status); - int (*get_adapter_status) (struct slot *slot, u8 *status); - - int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - - int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value); - int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value); - - int (*query_power_fault) (struct slot *slot); - void (*green_led_on) (struct slot *slot); - void (*green_led_off) (struct slot *slot); - void (*green_led_blink) (struct slot *slot); - void (*release_ctlr) (struct controller *ctrl); - int (*check_lnk_status) (struct controller *ctrl); -}; - +#endif /* CONFIG_ACPI */ #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c new file mode 100644 index 00000000000..93cc9266e8c --- /dev/null +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -0,0 +1,137 @@ +/* + * ACPI related functions for PCI Express Hot Plug driver. + * + * Copyright (C) 2008 Kenji Kaneshige + * Copyright (C) 2008 Fujitsu Limited. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/acpi.h> +#include <linux/pci.h> +#include <linux/pci_hotplug.h> +#include <linux/slab.h> +#include <linux/module.h> +#include "pciehp.h" + +#define PCIEHP_DETECT_PCIE (0) +#define PCIEHP_DETECT_ACPI (1) +#define PCIEHP_DETECT_AUTO (2) +#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO + +struct dummy_slot { + u32 number; + struct list_head list; +}; + +static int slot_detection_mode; +static char *pciehp_detect_mode; +module_param(pciehp_detect_mode, charp, 0444); +MODULE_PARM_DESC(pciehp_detect_mode, + "Slot detection mode: pcie, acpi, auto\n" + " pcie - Use PCIe based slot detection\n" + " acpi - Use ACPI for slot detection\n" + " auto(default) - Auto select mode. Use acpi option if duplicate\n" + " slot ids are found. Otherwise, use pcie option\n"); + +int pciehp_acpi_slot_detection_check(struct pci_dev *dev) +{ + if (slot_detection_mode != PCIEHP_DETECT_ACPI) + return 0; + if (acpi_pci_detect_ejectable(ACPI_HANDLE(&dev->dev))) + return 0; + return -ENODEV; +} + +static int __init parse_detect_mode(void) +{ + if (!pciehp_detect_mode) + return PCIEHP_DETECT_DEFAULT; + if (!strcmp(pciehp_detect_mode, "pcie")) + return PCIEHP_DETECT_PCIE; + if (!strcmp(pciehp_detect_mode, "acpi")) + return PCIEHP_DETECT_ACPI; + if (!strcmp(pciehp_detect_mode, "auto")) + return PCIEHP_DETECT_AUTO; + warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", + pciehp_detect_mode); + return PCIEHP_DETECT_DEFAULT; +} + +static int __initdata dup_slot_id; +static int __initdata acpi_slot_detected; +static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); + +/* Dummy driver for duplicate name detection */ +static int __init dummy_probe(struct pcie_device *dev) +{ + u32 slot_cap; + acpi_handle handle; + struct dummy_slot *slot, *tmp; + struct pci_dev *pdev = dev->port; + + pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + slot->number = (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19; + list_for_each_entry(tmp, &dummy_slots, list) { + if (tmp->number == slot->number) + dup_slot_id++; + } + list_add_tail(&slot->list, &dummy_slots); + handle = ACPI_HANDLE(&pdev->dev); + if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) + acpi_slot_detected = 1; + return -ENODEV; /* dummy driver always returns error */ +} + +static struct pcie_port_service_driver __initdata dummy_driver = { + .name = "pciehp_dummy", + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_HP, + .probe = dummy_probe, +}; + +static int __init select_detection_mode(void) +{ + struct dummy_slot *slot, *tmp; + + if (pcie_port_service_register(&dummy_driver)) + return PCIEHP_DETECT_ACPI; + pcie_port_service_unregister(&dummy_driver); + list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { + list_del(&slot->list); + kfree(slot); + } + if (acpi_slot_detected && dup_slot_id) + return PCIEHP_DETECT_ACPI; + return PCIEHP_DETECT_PCIE; +} + +void __init pciehp_acpi_slot_detection_init(void) +{ + slot_detection_mode = parse_detect_mode(); + if (slot_detection_mode != PCIEHP_DETECT_AUTO) + goto out; + slot_detection_mode = select_detection_mode(); +out: + if (slot_detection_mode == PCIEHP_DETECT_ACPI) + info("Using ACPI for slot detection.\n"); +} diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index cafc7eadcf8..a2297db8081 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -27,27 +27,21 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> #include <linux/slab.h> -#include <linux/workqueue.h> +#include <linux/types.h> #include <linux/pci.h> -#include <linux/init.h> -#include <asm/uaccess.h> #include "pciehp.h" -#include "pciehprm.h" #include <linux/interrupt.h> +#include <linux/time.h> /* Global variables */ -int pciehp_debug; -int pciehp_poll_mode; +bool pciehp_debug; +bool pciehp_poll_mode; int pciehp_poll_time; -struct controller *pciehp_ctrl_list; -struct pci_func *pciehp_slot_list[256]; +static bool pciehp_force; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" @@ -60,13 +54,14 @@ MODULE_LICENSE("GPL"); module_param(pciehp_debug, bool, 0644); module_param(pciehp_poll_mode, bool, 0644); module_param(pciehp_poll_time, int, 0644); +module_param(pciehp_force, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); +MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing"); #define PCIE_MODULE_NAME "pciehp" -static int pcie_start_thread (void); static int set_attention_status (struct hotplug_slot *slot, u8 value); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); @@ -74,21 +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_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); - -static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; +static int reset_slot (struct hotplug_slot *slot, int probe); /** * release_slot - free up the memory used by a slot @@ -98,147 +79,78 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, hotplug_slot_name(hotplug_slot)); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); + kfree(hotplug_slot->ops); + kfree(hotplug_slot->info); + kfree(hotplug_slot); } -static int init_slots(struct controller *ctrl) +static int init_slot(struct controller *ctrl) { - struct slot *new_slot; - u8 number_of_slots; - u8 slot_device; - u32 slot_number; - int result = -ENOMEM; - - dbg("%s\n",__FUNCTION__); - - number_of_slots = ctrl->num_slots; - slot_device = ctrl->slot_device_offset; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - if (!new_slot) - goto error; - - memset(new_slot, 0, sizeof(struct slot)); - new_slot->hotplug_slot = - kmalloc(sizeof(*(new_slot->hotplug_slot)), - GFP_KERNEL); - if (!new_slot->hotplug_slot) - goto error_slot; - memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - - new_slot->hotplug_slot->info = - kmalloc(sizeof(*(new_slot->hotplug_slot->info)), - GFP_KERNEL); - if (!new_slot->hotplug_slot->info) - goto error_hpslot; - memset(new_slot->hotplug_slot->info, 0, - sizeof(struct hotplug_slot_info)); - new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, - GFP_KERNEL); - if (!new_slot->hotplug_slot->name) - goto error_info; - - new_slot->ctrl = ctrl; - new_slot->bus = ctrl->slot_bus; - new_slot->device = slot_device; - new_slot->hpc_ops = ctrl->hpc_ops; - - new_slot->number = ctrl->first_slot; - new_slot->hp_slot = slot_device - ctrl->slot_device_offset; - - /* register this slot with the hotplug pci core */ - new_slot->hotplug_slot->private = new_slot; - new_slot->hotplug_slot->release = &release_slot; - make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); - new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops; - - new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); - new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status)); - new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status)); - new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status)); - - dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", - new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset); - result = pci_hp_register (new_slot->hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - goto error_name; - } - - new_slot->next = ctrl->slot; - ctrl->slot = new_slot; - - number_of_slots--; - slot_device++; - slot_number += ctrl->slot_num_inc; + struct slot *slot = ctrl->slot; + struct hotplug_slot *hotplug = NULL; + struct hotplug_slot_info *info = NULL; + struct hotplug_slot_ops *ops = NULL; + char name[SLOT_NAME_SIZE]; + int retval = -ENOMEM; + + hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL); + if (!hotplug) + goto out; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + goto out; + + /* Setup hotplug slot ops */ + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + goto out; + + ops->enable_slot = enable_slot; + ops->disable_slot = disable_slot; + ops->get_power_status = get_power_status; + ops->get_adapter_status = get_adapter_status; + ops->reset_slot = reset_slot; + if (MRL_SENS(ctrl)) + ops->get_latch_status = get_latch_status; + if (ATTN_LED(ctrl)) { + ops->get_attention_status = get_attention_status; + ops->set_attention_status = set_attention_status; } - return 0; - -error_name: - kfree(new_slot->hotplug_slot->name); -error_info: - kfree(new_slot->hotplug_slot->info); -error_hpslot: - kfree(new_slot->hotplug_slot); -error_slot: - kfree(new_slot); -error: - return result; -} - - -static int cleanup_slots (struct controller * ctrl) -{ - struct slot *old_slot, *next_slot; - - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister (old_slot->hotplug_slot); - old_slot = next_slot; + /* register this slot with the hotplug pci core */ + hotplug->info = info; + hotplug->private = slot; + hotplug->release = &release_slot; + hotplug->ops = ops; + slot->hotplug_slot = hotplug; + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:00 sun=%x\n", + pci_domain_nr(ctrl->pcie->port->subordinate), + ctrl->pcie->port->subordinate->number, PSN(ctrl)); + retval = pci_hp_register(hotplug, + ctrl->pcie->port->subordinate, 0, name); + if (retval) + ctrl_err(ctrl, + "pci_hp_register failed with error %d\n", retval); +out: + if (retval) { + kfree(ops); + kfree(info); + kfree(hotplug); } - - - return(0); + return retval; } -static int get_ctlr_slot_config(struct controller *ctrl) +static void cleanup_slot(struct controller *ctrl) { - int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/ - int first_device_num; /* Not needed */ - int physical_slot_num; - u8 ctrlcap; - int rc; - - rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap); - if (rc) { - err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); - return (-1); - } - - ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */ - ctrl->slot_device_offset = first_device_num; - ctrl->first_slot = physical_slot_num; - ctrl->ctrlcap = ctrlcap; - - dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n", - __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, - ctrl->bus, ctrl->device); - - return (0); + pci_hp_deregister(ctrl->slot->hotplug_slot); } - /* * set_attention_status - Turns the Amber LED for a slot on, off or blink */ @@ -246,13 +158,10 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - hotplug_slot->info->attention_status = status; - - if (ATTN_LED(slot->ctrl->ctrlcap)) - slot->hpc_ops->set_attention_status(slot, status); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); + pciehp_set_attention_status(slot, status); return 0; } @@ -261,9 +170,10 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); - return pciehp_enable_slot(slot); + return pciehp_sysfs_enable_slot(slot); } @@ -271,352 +181,170 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); - return pciehp_disable_slot(slot); + return pciehp_sysfs_disable_slot(slot); } static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - retval = slot->hpc_ops->get_power_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->power_status; + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); + pciehp_get_power_status(slot, value); return 0; } static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_attention_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->attention_status; + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); + pciehp_get_attention_status(slot, value); return 0; } static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - retval = slot->hpc_ops->get_latch_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->latch_status; + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); + pciehp_get_latch_status(slot, value); return 0; } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_adapter_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->adapter_status; + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); + pciehp_get_adapter_status(slot, value); return 0; } -static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static int reset_slot(struct hotplug_slot *hotplug_slot, int probe) { struct slot *slot = hotplug_slot->private; - int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_max_bus_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); - return 0; + return pciehp_reset_slot(slot, probe); } -static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = hotplug_slot->private; - int retval; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_cur_bus_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - -static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id) +static int pciehp_probe(struct pcie_device *dev) { int rc; struct controller *ctrl; - struct slot *t_slot; - int first_device_num = 0 ; /* first PCI device number supported by this PCIE */ - int num_ctlr_slots; /* number of slots supported by this HPC */ - u8 value; - struct pci_dev *pdev; - - dbg("%s: Called by hp_drv\n", __FUNCTION__); - ctrl = kmalloc(sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __FUNCTION__); + struct slot *slot; + u8 occupied, poweron; + + if (pciehp_force) + dev_info(&dev->device, + "Bypassing BIOS check for pciehp use on %s\n", + pci_name(dev->port)); + else if (pciehp_acpi_slot_detection_check(dev->port)) goto err_out_none; - } - memset(ctrl, 0, sizeof(struct controller)); - - dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); - - pdev = dev->port; - - rc = pcie_init(ctrl, dev, - (php_intr_callback_t) pciehp_handle_attention_button, - (php_intr_callback_t) pciehp_handle_switch_change, - (php_intr_callback_t) pciehp_handle_presence_change, - (php_intr_callback_t) pciehp_handle_power_fault); - if (rc) { - dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); - goto err_out_free_ctrl; - } - - ctrl->pci_dev = pdev; - - pci_set_drvdata(pdev, ctrl); - - ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("%s: out of memory\n", __FUNCTION__); - rc = -ENOMEM; - goto err_out_unmap_mmio_region; - } - dbg("%s: ctrl->pci_bus %p\n", __FUNCTION__, ctrl->pci_bus); - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); - ctrl->bus = pdev->bus->number; /* ctrl bus */ - ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ - - ctrl->device = PCI_SLOT(pdev->devfn); - ctrl->function = PCI_FUNC(pdev->devfn); - dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, - ctrl->bus, ctrl->device, ctrl->function, pdev->irq); - - /* - * Save configuration headers for this and subordinate PCI buses - */ - - rc = get_ctlr_slot_config(ctrl); - if (rc) { - err(msg_initialization_err, rc); - goto err_out_free_ctrl_bus; - } - first_device_num = ctrl->slot_device_offset; - num_ctlr_slots = ctrl->num_slots; - /* Store PCI Config Space for all devices on this bus */ - dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", - __FUNCTION__,ctrl->bus, ctrl->slot_bus); - rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); - if (rc) { - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_out_free_ctrl_bus; + ctrl = pcie_init(dev); + if (!ctrl) { + dev_err(&dev->device, "Controller initialization failed\n"); + goto err_out_none; } + set_service_data(dev, ctrl); - /* Get IO, memory, and IRQ resources for new devices */ - rc = pciehprm_find_available_resources(ctrl); - ctrl->add_support = !rc; - + /* Setup the slot information structures */ + rc = init_slot(ctrl); if (rc) { - dbg("pciehprm_find_available_resources = %#x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_out_free_ctrl_bus; + if (rc == -EBUSY) + ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n"); + else + ctrl_err(ctrl, "Slot initialization failed\n"); + goto err_out_release_ctlr; } - /* Setup the slot information structures */ - rc = init_slots(ctrl); + /* Enable events after we have setup the data structures */ + rc = pcie_init_notification(ctrl); if (rc) { - err(msg_initialization_err, 6); + ctrl_err(ctrl, "Notification initialization failed\n"); goto err_out_free_ctrl_slot; } - t_slot = pciehp_find_slot(ctrl, first_device_num); - dbg("%s: t_slot %p\n", __FUNCTION__, t_slot); - - /* Finish setting up the hot plug ctrl device */ - ctrl->next_event = 0; - - if (!pciehp_ctrl_list) { - pciehp_ctrl_list = ctrl; - ctrl->next = NULL; - } else { - ctrl->next = pciehp_ctrl_list; - pciehp_ctrl_list = ctrl; - } - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ - dbg("%s: adpater value %x\n", __FUNCTION__, value); - - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { - rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ - if (rc) { - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - goto err_out_free_ctrl_slot; - } else - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + /* Check if slot is occupied */ + slot = ctrl->slot; + pciehp_get_adapter_status(slot, &occupied); + pciehp_get_power_status(slot, &poweron); + if (occupied && pciehp_force) { + mutex_lock(&slot->hotplug_lock); + pciehp_enable_slot(slot); + mutex_unlock(&slot->hotplug_lock); } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + /* If empty slot's power status is on, turn power off */ + if (!occupied && poweron && POWER_CTRL(ctrl)) + pciehp_power_off_slot(slot); return 0; err_out_free_ctrl_slot: - cleanup_slots(ctrl); -err_out_free_ctrl_bus: - kfree(ctrl->pci_bus); -err_out_unmap_mmio_region: - ctrl->hpc_ops->release_ctlr(ctrl); -err_out_free_ctrl: - kfree(ctrl); + cleanup_slot(ctrl); +err_out_release_ctlr: + pciehp_release_ctrl(ctrl); err_out_none: return -ENODEV; } - -static int pcie_start_thread(void) +static void pciehp_remove(struct pcie_device *dev) { - int loop; - int retval = 0; - - dbg("Initialize + Start the notification/polling mechanism \n"); + struct controller *ctrl = get_service_data(dev); - retval = pciehp_event_start_thread(); - if (retval) { - dbg("pciehp_event_start_thread() failed\n"); - return retval; - } - - dbg("Initialize slot lists\n"); - /* One slot list for each bus in the system */ - for (loop = 0; loop < 256; loop++) { - pciehp_slot_list[loop] = NULL; - } - - return retval; + cleanup_slot(ctrl); + pciehp_release_ctrl(ctrl); } -static inline void __exit -free_pciehp_res(struct pci_resource *res) +#ifdef CONFIG_PM +static int pciehp_suspend(struct pcie_device *dev) { - struct pci_resource *tres; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } + return 0; } -static void __exit unload_pciehpd(void) +static int pciehp_resume(struct pcie_device *dev) { - struct pci_func *next; - struct pci_func *TempSlot; - int loop; struct controller *ctrl; - struct controller *tctrl; - - ctrl = pciehp_ctrl_list; - - while (ctrl) { - cleanup_slots(ctrl); - - free_pciehp_res(ctrl->io_head); - free_pciehp_res(ctrl->mem_head); - free_pciehp_res(ctrl->p_mem_head); - free_pciehp_res(ctrl->bus_head); + struct slot *slot; + u8 status; - kfree (ctrl->pci_bus); + ctrl = get_service_data(dev); - ctrl->hpc_ops->release_ctlr(ctrl); + /* reinitialize the chipset's event detection logic */ + pcie_enable_notification(ctrl); - tctrl = ctrl; - ctrl = ctrl->next; + slot = ctrl->slot; - kfree(tctrl); - } - - for (loop = 0; loop < 256; loop++) { - next = pciehp_slot_list[loop]; - while (next != NULL) { - free_pciehp_res(next->io_head); - free_pciehp_res(next->mem_head); - free_pciehp_res(next->p_mem_head); - free_pciehp_res(next->bus_head); - - TempSlot = next; - next = next->next; - kfree(TempSlot); - } - } - - /* Stop the notification mechanism */ - pciehp_event_stop_thread(); - -} - -int hpdriver_context = 0; - -static void pciehp_remove (struct pcie_device *device) -{ - printk("%s ENTRY\n", __FUNCTION__); - printk("%s -> Call free_irq for irq = %d\n", - __FUNCTION__, device->irq); - free_irq(device->irq, &hpdriver_context); -} - -#ifdef CONFIG_PM -static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) -{ - printk("%s ENTRY\n", __FUNCTION__); + /* Check if slot is occupied */ + pciehp_get_adapter_status(slot, &status); + mutex_lock(&slot->hotplug_lock); + if (status) + pciehp_enable_slot(slot); + else + pciehp_disable_slot(slot); + mutex_unlock(&slot->hotplug_lock); return 0; } - -static int pciehp_resume (struct pcie_device *dev) -{ - printk("%s ENTRY\n", __FUNCTION__); - return 0; -} -#endif - -static struct pcie_port_service_id port_pci_ids[] = { { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .port_type = PCIE_ANY_PORT, - .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, - }, { /* end: all zeroes */ } -}; -static const char device_name[] = "hpdriver"; +#endif /* PM */ static struct pcie_port_service_driver hpdriver_portdrv = { - .name = (char *)device_name, - .id_table = &port_pci_ids[0], + .name = PCIE_MODULE_NAME, + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_HP, .probe = pciehp_probe, .remove = pciehp_remove, @@ -631,29 +359,12 @@ static int __init pcied_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - pciehp_poll_mode = 1; -#endif - - retval = pcie_start_thread(); + pciehp_firmware_init(); + retval = pcie_port_service_register(&hpdriver_portdrv); + dbg("pcie_port_service_register = %d\n", retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); if (retval) - goto error_hpc_init; - - retval = pciehprm_init(PCI); - if (!retval) { - retval = pcie_port_service_register(&hpdriver_portdrv); - dbg("pcie_port_service_register = %d\n", retval); - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - if (retval) - dbg("%s: Failure to register service\n", __FUNCTION__); - } - -error_hpc_init: - if (retval) { - pciehprm_cleanup(); - pciehp_event_stop_thread(); - } else - pciehprm_print_pirt(); + dbg("Failure to register service\n"); return retval; } @@ -661,13 +372,7 @@ error_hpc_init: static void __exit pcied_cleanup(void) { dbg("unload_pciehpd()\n"); - unload_pciehpd(); - - pciehprm_cleanup(); - - dbg("pcie_port_service_unregister\n"); pcie_port_service_unregister(&hpdriver_portdrv); - info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 898f6da6f0d..ff32e85e1de 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -27,2678 +27,668 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/smp_lock.h> #include <linux/pci.h> #include "../pci.h" #include "pciehp.h" -#include "pciehprm.h" -static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); -static int configure_new_function( struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); -static void interrupt_event_handler(struct controller *ctrl); +static void interrupt_event_handler(struct work_struct *work); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ -static unsigned long surprise_rm_pending; /* = 0 */ - -u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) +static int queue_interrupt_event(struct slot *p_slot, u32 event_type) { - struct controller *ctrl = (struct controller *) inst_id; - struct slot *p_slot; - u8 rc = 0; - u8 getstatus; - struct pci_func *func; - struct event_info *taskInfo; + struct event_info *info; - /* Attention Button Change */ - dbg("pciehp: Attention button interrupt received.\n"); - - func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + info = kmalloc(sizeof(*info), GFP_ATOMIC); + if (!info) + return -ENOMEM; + + info->event_type = event_type; + info->p_slot = p_slot; + INIT_WORK(&info->work, interrupt_event_handler); + + queue_work(p_slot->wq, &info->work); - /* This is the structure that tells the worker thread what to do */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + return 0; +} - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; +u8 pciehp_handle_attention_button(struct slot *p_slot) +{ + u32 event_type; + struct controller *ctrl = p_slot->ctrl; - rc++; + /* Attention Button Change */ + ctrl_dbg(ctrl, "Attention button interrupt received\n"); /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_BUTTON_PRESS; - - if ((p_slot->state == BLINKINGON_STATE) - || (p_slot->state == BLINKINGOFF_STATE)) { - /* Cancel if we are still blinking; this means that we press the - * attention again before the 5 sec. limit expires to cancel hot-add - * or hot-remove - */ - taskInfo->event_type = INT_BUTTON_CANCEL; - info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); - } else if ((p_slot->state == POWERON_STATE) - || (p_slot->state == POWEROFF_STATE)) { - /* Ignore if the slot is on power-on or power-off state; this - * means that the previous attention button action to hot-add or - * hot-remove is undergoing - */ - taskInfo->event_type = INT_BUTTON_IGNORE; - info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); - } + ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_BUTTON_PRESS; - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); return 0; - } -u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_switch_change(struct slot *p_slot) { - struct controller *ctrl = (struct controller *) inst_id; - struct slot *p_slot; - u8 rc = 0; u8 getstatus; - struct pci_func *func; - struct event_info *taskInfo; + u32 event_type; + struct controller *ctrl = p_slot->ctrl; /* Switch Change */ - dbg("pciehp: Switch interrupt received.\n"); - - func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - - /* This is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + ctrl_dbg(ctrl, "Switch interrupt received\n"); + pciehp_get_latch_status(p_slot, &getstatus); if (getstatus) { /* * Switch opened */ - info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0; - taskInfo->event_type = INT_SWITCH_OPEN; + ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0x10; - taskInfo->event_type = INT_SWITCH_CLOSE; + ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_SWITCH_CLOSE; } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); - return rc; + return 1; } -u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_presence_change(struct slot *p_slot) { - struct controller *ctrl = (struct controller *) inst_id; - struct slot *p_slot; - u8 rc = 0; - struct pci_func *func; - struct event_info *taskInfo; + u32 event_type; + u8 presence_save; + struct controller *ctrl = p_slot->ctrl; /* Presence Change */ - dbg("pciehp: Presence/Notify input change.\n"); - - func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - - /* This is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + ctrl_dbg(ctrl, "Presence/Notify input change\n"); /* Switch is open, assume a presence change * Save the presence state */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - if (func->presence_save) { + pciehp_get_adapter_status(p_slot, &presence_save); + if (presence_save) { /* * Card Present */ - info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_PRESENCE_ON; + ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_PRESENCE_OFF; + ctrl_info(ctrl, "Card not present on Slot(%s)\n", + slot_name(p_slot)); + event_type = INT_PRESENCE_OFF; } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); - return rc; + return 1; } -u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) +u8 pciehp_handle_power_fault(struct slot *p_slot) { - struct controller *ctrl = (struct controller *) inst_id; - struct slot *p_slot; - u8 rc = 0; - struct pci_func *func; - struct event_info *taskInfo; + u32 event_type; + struct controller *ctrl = p_slot->ctrl; /* power fault */ - dbg("pciehp: Power fault interrupt received.\n"); - - func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - - /* this is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; + ctrl_dbg(ctrl, "Power fault interrupt received\n"); + ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); + event_type = INT_POWER_FAULT; + ctrl_info(ctrl, "Power fault bit %x set\n", 0); + queue_interrupt_event(p_slot, event_type); - rc++; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { - /* - * power fault Cleared - */ - info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->status = 0x00; - taskInfo->event_type = INT_POWER_FAULT_CLEAR; - } else { - /* - * power fault - */ - info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_POWER_FAULT; - /* set power fault status for this board */ - func->status = 0xFF; - info("power fault bit %x set\n", hp_slot); - } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ - - return rc; + return 1; } - -/** - * sort_by_size: sort nodes by their length, smallest first. - * - * @head: list to sort - */ -static int sort_by_size(struct pci_resource **head) +void pciehp_handle_linkstate_change(struct slot *p_slot) { - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; + u32 event_type; + struct controller *ctrl = p_slot->ctrl; - while (out_of_order) { - out_of_order = 0; + /* Link Status Change */ + ctrl_dbg(ctrl, "Data Link Layer State change\n"); - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ + if (pciehp_check_link_active(ctrl)) { + ctrl_info(ctrl, "slot(%s): Link Up event\n", + slot_name(p_slot)); + event_type = INT_LINK_UP; + } else { + ctrl_info(ctrl, "slot(%s): Link Down event\n", + slot_name(p_slot)); + event_type = INT_LINK_DOWN; + } - return 0; + queue_interrupt_event(p_slot, event_type); } - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * +/* The following routines constitute the bulk of the + hotplug controller logic */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - - -/** - * do_pre_bridge_resource_split: return one unused resource node - * @head: list to scan - * - */ -static struct pci_resource * -do_pre_bridge_resource_split(struct pci_resource **head, - struct pci_resource **orig_head, u32 alignment) +static void set_slot_off(struct controller *ctrl, struct slot *pslot) { - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return NULL; - - rc = pciehp_resource_sort_and_combine(head); - - if (rc) - return NULL; - - if ((*head)->base != (*orig_head)->base) - return NULL; - - if ((*head)->length == (*orig_head)->length) - return NULL; - - - /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front - */ - node = *head; + /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ + if (POWER_CTRL(ctrl)) { + pciehp_power_off_slot(pslot); - if (node->length & (alignment -1)) { - /* this one isn't an aligned length, so we'll make a new entry - * and split it up. + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. */ - split_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return NULL; - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - /* Put it in the list */ - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) - return NULL; - - /* Now unlink it */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; + msleep(1000); } - node->next = NULL; - return node; + pciehp_green_led_off(pslot); + pciehp_set_attention_status(pslot, 1); } - /** - * do_bridge_resource_split: return one unused resource node - * @head: list to scan - * - */ -static struct pci_resource * -do_bridge_resource_split(struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return NULL; - - rc = pciehp_resource_sort_and_combine(head); - - if (rc) - return NULL; - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return NULL; - } - - if (node->base & (alignment - 1)) { - /* Short circuit if adjusted size is too small */ - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return NULL; - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - /* There's stuff in use after this node */ - kfree(node); - return NULL; - } - - return node; -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. + * board_added - Called after a board has been added to the system. + * @p_slot: &slot where board is added * - * size must be a power of two. + * Turns power on for the board. + * Configures board. */ -static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size) +static int board_added(struct slot *p_slot) { - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node = NULL; - u32 temp_dword; - - if (!(*head)) - return NULL; - - if ( pciehp_resource_sort_and_combine(head) ) - return NULL; - - if ( sort_by_size(head) ) - return NULL; - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /*/ Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; + int retval = 0; + struct controller *ctrl = p_slot->ctrl; + struct pci_bus *parent = ctrl->pcie->port->subordinate; - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; + if (POWER_CTRL(ctrl)) { + /* Power on slot */ + retval = pciehp_power_on_slot(p_slot); + if (retval) + return retval; } - return node; -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M - * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. - */ -static struct pci_resource *get_max_resource(struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; - int i; - - if (!(*head)) - return NULL; - - if (pciehp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_max_size(head)) - return NULL; + pciehp_green_led_blink(p_slot); - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* this one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - for ( i = 0; max_size[i] > size; i++) { - if (max->length > max_size[i]) { - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!split_node) - break; /* return NULL; */ - split_node->base = max->base + max_size[i]; - split_node->length = max->length - max_size[i]; - max->length = max_size[i]; - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - break; - } - } - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return max; + /* Check link training status */ + retval = pciehp_check_link_status(ctrl); + if (retval) { + ctrl_err(ctrl, "Failed to check link status\n"); + goto err_exit; } - /* If we get here, we couldn't find one */ - return NULL; -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource(struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return NULL; - - if ( pciehp_resource_sort_and_combine(head) ) - return NULL; - - if ( sort_by_size(head) ) - return NULL; - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - - if (!split_node) - return NULL; - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; + /* Check for a power fault */ + if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { + ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); + retval = -EIO; + goto err_exit; } - return node; -} - - -/* - * pciehp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int pciehp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - if (!(*head)) - return 1; - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return 0; /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; + retval = pciehp_configure_device(p_slot); + if (retval) { + ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", + pci_domain_nr(parent), parent->number); + if (retval != -EEXIST) + goto err_exit; } + pciehp_green_led_on(p_slot); return 0; -} - -/** - * pciehp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located - * - * Returns pointer to the new node or NULL if unsuccessful - */ -struct pci_func *pciehp_slot_create(u8 busnumber) -{ - struct pci_func *new_slot; - struct pci_func *next; - dbg("%s: busnumber %x\n", __FUNCTION__, busnumber); - new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL); - - if (new_slot == NULL) - return new_slot; - - memset(new_slot, 0, sizeof(struct pci_func)); - - new_slot->next = NULL; - new_slot->configured = 1; - - if (pciehp_slot_list[busnumber] == NULL) { - pciehp_slot_list[busnumber] = new_slot; - } else { - next = pciehp_slot_list[busnumber]; - while (next->next != NULL) - next = next->next; - next->next = new_slot; - } - return new_slot; +err_exit: + set_slot_off(ctrl, p_slot); + return retval; } - -/** - * slot_remove - Removes a node from the linked list of slots. - * @old_slot: slot to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int slot_remove(struct pci_func * old_slot) -{ - struct pci_func *next; - - if (old_slot == NULL) - return 1; - - next = pciehp_slot_list[old_slot->bus]; - - if (next == NULL) - return 1; - - if (next == old_slot) { - pciehp_slot_list[old_slot->bus] = old_slot->next; - pciehp_destroy_board_resources(old_slot); - kfree(old_slot); - return 0; - } - - while ((next->next != old_slot) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == old_slot) { - next->next = old_slot->next; - pciehp_destroy_board_resources(old_slot); - kfree(old_slot); - return 0; - } else - return 2; -} - - /** - * bridge_slot_remove - Removes a node from the linked list of slots. - * @bridge: bridge to remove - * - * Returns 0 if successful, !0 otherwise. + * remove_board - Turns off slot and LEDs + * @p_slot: slot where board is being removed */ -static int bridge_slot_remove(struct pci_func *bridge) +static int remove_board(struct slot *p_slot) { - u8 subordinateBus, secondaryBus; - u8 tempBus; - struct pci_func *next; + int retval; + struct controller *ctrl = p_slot->ctrl; - if (bridge == NULL) - return 1; + retval = pciehp_unconfigure_device(p_slot); + if (retval) + return retval; - secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; - subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + if (POWER_CTRL(ctrl)) { + pciehp_power_off_slot(p_slot); - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { - next = pciehp_slot_list[tempBus]; - - while (!slot_remove(next)) { - next = pciehp_slot_list[tempBus]; - } - } - - next = pciehp_slot_list[bridge->bus]; - - if (next == NULL) { - return 1; - } - - if (next == bridge) { - pciehp_slot_list[bridge->bus] = bridge->next; - kfree(bridge); - return 0; - } - - while ((next->next != bridge) && (next->next != NULL)) { - next = next->next; + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. + */ + msleep(1000); } - if (next->next == bridge) { - next->next = bridge->next; - kfree(bridge); - return 0; - } else - return 2; + /* turn off Green LED */ + pciehp_green_led_off(p_slot); + return 0; } +struct power_work_info { + struct slot *p_slot; + struct work_struct work; + unsigned int req; +#define DISABLE_REQ 0 +#define ENABLE_REQ 1 +}; /** - * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed - * @bus: bus to find - * @device: device to find - * @index: is 0 for first function found, 1 for the second... + * pciehp_power_thread - handle pushbutton events + * @work: &struct work_struct describing work to be done * - * Returns pointer to the node if successful, %NULL otherwise. + * Scheduled procedure to handle blocking stuff for the pushbuttons. + * Handles all pending events and exits. */ -struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index) -{ - int found = -1; - struct pci_func *func; - - func = pciehp_slot_list[bus]; - dbg("%s: bus %x device %x index %x\n", - __FUNCTION__, bus, device, index); - if (func != NULL) { - dbg("%s: func-> bus %x device %x function %x pci_dev %p\n", - __FUNCTION__, func->bus, func->device, func->function, - func->pci_dev); - } else - dbg("%s: func == NULL\n", __FUNCTION__); - - if ((func == NULL) || ((func->device == device) && (index == 0))) - return func; - - if (func->device == device) - found++; - - while (func->next != NULL) { - func = func->next; - - dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n", - __FUNCTION__, func->bus, func->device, func->function, - func->pci_dev); - if (func->device == device) - found++; - dbg("%s: while loop, found %d, index %d\n", __FUNCTION__, - found, index); - - if ((found == index) || (func->function == index)) { - dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__, - func->bus, func->device, func->function); - return func; - } +static void pciehp_power_thread(struct work_struct *work) +{ + struct power_work_info *info = + container_of(work, struct power_work_info, work); + struct slot *p_slot = info->p_slot; + int ret; + + switch (info->req) { + case DISABLE_REQ: + ctrl_dbg(p_slot->ctrl, + "Disabling domain:bus:device=%04x:%02x:00\n", + pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), + p_slot->ctrl->pcie->port->subordinate->number); + mutex_lock(&p_slot->hotplug_lock); + pciehp_disable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + mutex_unlock(&p_slot->lock); + break; + case ENABLE_REQ: + ctrl_dbg(p_slot->ctrl, + "Enabling domain:bus:device=%04x:%02x:00\n", + pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), + p_slot->ctrl->pcie->port->subordinate->number); + mutex_lock(&p_slot->hotplug_lock); + ret = pciehp_enable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); + if (ret) + pciehp_green_led_off(p_slot); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + mutex_unlock(&p_slot->lock); + break; + default: + break; } - return NULL; -} - -static int is_bridge(struct pci_func * func) -{ - /* Check the header type */ - if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) - return 1; - else - return 0; + kfree(info); } - -/* The following routines constitute the bulk of the - hotplug controller logic - */ - -static void set_slot_off(struct controller *ctrl, struct slot * pslot) +void pciehp_queue_pushbutton_work(struct work_struct *work) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ - if (POWER_CTRL(ctrl->ctrlcap)) { - if (pslot->hpc_ops->power_off_slot(pslot)) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return; - } - wait_for_ctrl_irq (ctrl); - } + struct slot *p_slot = container_of(work, struct slot, work.work); + struct power_work_info *info; - if (PWR_LED(ctrl->ctrlcap)) { - pslot->hpc_ops->green_led_off(pslot); - wait_for_ctrl_irq (ctrl); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); + return; } + info->p_slot = p_slot; + INIT_WORK(&info->work, pciehp_power_thread); - if (ATTN_LED(ctrl->ctrlcap)) { - if (pslot->hpc_ops->set_attention_status(pslot, 1)) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return; - } - wait_for_ctrl_irq (ctrl); + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGOFF_STATE: + p_slot->state = POWEROFF_STATE; + info->req = DISABLE_REQ; + break; + case BLINKINGON_STATE: + p_slot->state = POWERON_STATE; + info->req = ENABLE_REQ; + break; + default: + kfree(info); + goto out; } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + queue_work(p_slot->wq, &info->work); + out: + mutex_unlock(&p_slot->lock); } -/** - * board_added - Called after a board has been added to the system. - * - * Turns power on for the board - * Configures board - * +/* + * Note: This function must be called with slot->lock held */ -static u32 board_added(struct pci_func * func, struct controller * ctrl) +static void handle_button_press_event(struct slot *p_slot) { - u8 hp_slot; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 rc = 0; - struct pci_func *new_func = NULL; - struct slot *p_slot; - struct resource_lists res_lists; - - p_slot = pciehp_find_slot(ctrl, func->device); - hp_slot = func->device - ctrl->slot_device_offset; - - dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - if (POWER_CTRL(ctrl->ctrlcap)) { - /* Power on slot */ - rc = p_slot->hpc_ops->power_on_slot(p_slot); - if (rc) { - up(&ctrl->crit_sect); - return -1; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - if (PWR_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->green_led_blink(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - /* Wait for ~1 second */ - dbg("%s: before long_delay\n", __FUNCTION__); - wait_for_ctrl_irq (ctrl); - dbg("%s: afterlong_delay\n", __FUNCTION__); - - /* Check link training status */ - rc = p_slot->hpc_ops->check_lnk_status(ctrl); - if (rc) { - err("%s: Failed to check link status\n", __FUNCTION__); - set_slot_off(ctrl, p_slot); - return rc; - } - - dbg("%s: func status = %x\n", __FUNCTION__, func->status); - - /* Check for a power fault */ - if (func->status == 0xFF) { - /* power fault occurred, but it was benign */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); - rc = POWER_FAILURE; - func->status = 0; - } else { - /* Get vendor/device ID u32 */ - rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), - PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - /* Something's wrong here */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - /* Preset return code. It will be changed later if things go okay. */ - rc = NO_ADAPTER_PRESENT; - } - - /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); - dbg("%s: back from configure_new_device\n", __FUNCTION__); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - pciehp_resource_sort_and_combine(&(ctrl->mem_head)); - pciehp_resource_sort_and_combine(&(ctrl->p_mem_head)); - pciehp_resource_sort_and_combine(&(ctrl->io_head)); - pciehp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - set_slot_off(ctrl, p_slot); - return rc; - } - pciehp_save_slot_config(ctrl, func); - - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; + struct controller *ctrl = p_slot->ctrl; + u8 getstatus; - /* next, we will instantiate the linux pci_dev structures - * (with appropriate driver notification, if already present) + switch (p_slot->state) { + case STATIC_STATE: + pciehp_get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = BLINKINGOFF_STATE; + ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", + slot_name(p_slot)); + } else { + p_slot->state = BLINKINGON_STATE; + ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", + slot_name(p_slot)); + } + /* blink green LED and turn off amber */ + pciehp_green_led_blink(p_slot); + pciehp_set_attention_status(p_slot, 0); + queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); + break; + case BLINKINGOFF_STATE: + case BLINKINGON_STATE: + /* + * Cancel if we are still blinking; this means that we + * press the attention again before the 5 sec. limit + * expires to cancel hot-add or hot-remove */ - index = 0; - do { - new_func = pciehp_slot_find(ctrl->slot_bus, func->device, index++); - if (new_func && !new_func->pci_dev) { - dbg("%s:call pci_hp_configure_dev, func %x\n", - __FUNCTION__, index); - pciehp_configure_device(ctrl, new_func); - } - } while (new_func); - - /* - * Some PCI Express root ports require fixup after hot-plug operation. - */ - if (pcie_mch_quirk) - pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - - if (PWR_LED(ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_on(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - } - } else { - set_slot_off(ctrl, p_slot); - return -1; - } - return 0; -} - - -/** - * remove_board - Turns off slot and LED's - * - */ -static u32 remove_board(struct pci_func *func, struct controller *ctrl) -{ - int index; - u8 skip = 0; - u8 device; - u8 hp_slot; - u32 rc; - struct resource_lists res_lists; - struct pci_func *temp_func; - struct slot *p_slot; - - if (func == NULL) - return 1; - - if (pciehp_unconfigure_device(func)) - return 1; - - device = func->device; - - hp_slot = func->device - ctrl->slot_device_offset; - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - - if ((ctrl->add_support) && - !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { - /* Here we check to see if we've saved any of the board's - * resources already. If so, we'll skip the attempt to - * determine what's being used. + ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); + cancel_delayed_work(&p_slot->work); + if (p_slot->state == BLINKINGOFF_STATE) + pciehp_green_led_on(p_slot); + else + pciehp_green_led_off(p_slot); + pciehp_set_attention_status(p_slot, 0); + ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", + slot_name(p_slot)); + p_slot->state = STATIC_STATE; + break; + case POWEROFF_STATE: + case POWERON_STATE: + /* + * Ignore if the slot is on power-on or power-off state; + * this means that the previous attention button action + * to hot-add or hot-remove is undergoing */ - index = 0; - - temp_func = func; - - while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, index++))) { - if (temp_func->bus_head || temp_func->mem_head - || temp_func->p_mem_head || temp_func->io_head) { - skip = 1; - break; - } - } - - if (!skip) - rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD); - } - /* Change status to shutdown */ - if (func->is_a_board) - func->status = 0x01; - func->configured = 0; - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - if (POWER_CTRL(ctrl->ctrlcap)) { - /* power off slot */ - rc = p_slot->hpc_ops->power_off_slot(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return rc; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - if (PWR_LED(ctrl->ctrlcap)) { - /* turn off Green LED */ - p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - if (ctrl->add_support) { - while (func) { - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - - dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", - func->bus, func->device, func->function); - - pciehp_return_board_resources(func, &res_lists); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - pciehp_resource_sort_and_combine(&(ctrl->mem_head)); - pciehp_resource_sort_and_combine(&(ctrl->p_mem_head)); - pciehp_resource_sort_and_combine(&(ctrl->io_head)); - pciehp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (is_bridge(func)) { - dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", - ctrl->seg, func->bus, func->device, func->function); - bridge_slot_remove(func); - } else { - dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", - ctrl->seg, func->bus, func->device, func->function); - slot_remove(func); - } - - func = pciehp_slot_find(ctrl->slot_bus, device, 0); - } - - /* Setup slot structure with entry for empty slot */ - func = pciehp_slot_create(ctrl->slot_bus); - - if (func == NULL) { - return 1; - } - - func->bus = ctrl->slot_bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->switch_save = 0x10; - func->is_a_board = 0; + ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); + break; + default: + ctrl_warn(ctrl, "Not a valid state\n"); + break; } - - return 0; -} - - -static void pushbutton_helper_thread(unsigned long data) -{ - pushbutton_pending = data; - - up(&event_semaphore); } -/** - * pciehp_pushbutton_thread - * - * Scheduled procedure to handle blocking stuff for the pushbuttons - * Handles all pending events and exits. - * +/* + * Note: This function must be called with slot->lock held */ -static void pciehp_pushbutton_thread(unsigned long slot) +static void handle_surprise_event(struct slot *p_slot) { - struct slot *p_slot = (struct slot *) slot; u8 getstatus; - - pushbutton_pending = 0; + struct power_work_info *info; - if (!p_slot) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); return; } + info->p_slot = p_slot; + INIT_WORK(&info->work, pciehp_power_thread); - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { + pciehp_get_adapter_status(p_slot, &getstatus); + if (!getstatus) { p_slot->state = POWEROFF_STATE; - dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - - pciehp_disable_slot(p_slot); - p_slot->state = STATIC_STATE; + info->req = DISABLE_REQ; } else { p_slot->state = POWERON_STATE; - dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - down(&p_slot->ctrl->crit_sect); - - p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - up(&p_slot->ctrl->crit_sect); - } - p_slot->state = STATIC_STATE; + info->req = ENABLE_REQ; } - return; + queue_work(p_slot->wq, &info->work); } -/** - * pciehp_surprise_rm_thread - * - * Scheduled procedure to handle blocking stuff for the surprise removal - * Handles all pending events and exits. - * +/* + * Note: This function must be called with slot->lock held */ -static void pciehp_surprise_rm_thread(unsigned long slot) +static void handle_link_event(struct slot *p_slot, u32 event) { - struct slot *p_slot = (struct slot *) slot; - u8 getstatus; - - surprise_rm_pending = 0; + struct controller *ctrl = p_slot->ctrl; + struct power_work_info *info; - if (!p_slot) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); return; } - - p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (!getstatus) { - p_slot->state = POWEROFF_STATE; - dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - - pciehp_disable_slot(p_slot); - p_slot->state = STATIC_STATE; - } else { - p_slot->state = POWERON_STATE; - dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - down(&p_slot->ctrl->crit_sect); - - p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - up(&p_slot->ctrl->crit_sect); + info->p_slot = p_slot; + info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ; + INIT_WORK(&info->work, pciehp_power_thread); + + switch (p_slot->state) { + case BLINKINGON_STATE: + case BLINKINGOFF_STATE: + cancel_delayed_work(&p_slot->work); + /* Fall through */ + case STATIC_STATE: + p_slot->state = event == INT_LINK_UP ? + POWERON_STATE : POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); + break; + case POWERON_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event ignored on slot(%s): already powering on\n", + slot_name(p_slot)); + kfree(info); + } else { + ctrl_info(ctrl, + "Link Down event queued on slot(%s): currently getting powered on\n", + slot_name(p_slot)); + p_slot->state = POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); } - p_slot->state = STATIC_STATE; + break; + case POWEROFF_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event queued on slot(%s): currently getting powered off\n", + slot_name(p_slot)); + p_slot->state = POWERON_STATE; + queue_work(p_slot->wq, &info->work); + } else { + ctrl_info(ctrl, + "Link Down event ignored on slot(%s): already powering off\n", + slot_name(p_slot)); + kfree(info); + } + break; + default: + ctrl_err(ctrl, "Not a valid state on slot(%s)\n", + slot_name(p_slot)); + kfree(info); + break; } - - return; } - - -/* this is the main worker thread */ -static int event_thread(void* data) +static void interrupt_event_handler(struct work_struct *work) { - struct controller *ctrl; - lock_kernel(); - daemonize("pciehpd_event"); + struct event_info *info = container_of(work, struct event_info, work); + struct slot *p_slot = info->p_slot; + struct controller *ctrl = p_slot->ctrl; - unlock_kernel(); - - while (1) { - dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished || signal_pending(current)) + mutex_lock(&p_slot->lock); + switch (info->event_type) { + case INT_BUTTON_PRESS: + handle_button_press_event(p_slot); + break; + case INT_POWER_FAULT: + if (!POWER_CTRL(ctrl)) break; - /* Do stuff here */ - if (pushbutton_pending) - pciehp_pushbutton_thread(pushbutton_pending); - else if (surprise_rm_pending) - pciehp_surprise_rm_thread(surprise_rm_pending); - else - for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) - interrupt_event_handler(ctrl); - } - dbg("event_thread signals exit\n"); - up(&event_exit); - return 0; -} - -int pciehp_event_start_thread(void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - init_MUTEX_LOCKED(&event_semaphore); - pid = kernel_thread(event_thread, NULL, 0); - - if (pid < 0) { - err ("Can't start up our event thread\n"); - return -1; + pciehp_set_attention_status(p_slot, 1); + pciehp_green_led_off(p_slot); + break; + case INT_PRESENCE_ON: + if (!HP_SUPR_RM(ctrl)) + break; + ctrl_dbg(ctrl, "Surprise Insertion\n"); + handle_surprise_event(p_slot); + break; + case INT_PRESENCE_OFF: + /* + * Regardless of surprise capability, we need to + * definitely remove a card that has been pulled out! + */ + ctrl_dbg(ctrl, "Surprise Removal\n"); + handle_surprise_event(p_slot); + break; + case INT_LINK_UP: + case INT_LINK_DOWN: + handle_link_event(p_slot, info->event_type); + break; + default: + break; } - dbg("Our event thread pid = %d\n", pid); - return 0; -} - - -void pciehp_event_stop_thread(void) -{ - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); -} - - -static int update_slot_info(struct slot *slot) -{ - struct hotplug_slot_info *info; - /* char buffer[SLOT_NAME_SIZE]; */ - int result; - - info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!info) - return -ENOMEM; + mutex_unlock(&p_slot->lock); - /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */ - - slot->hpc_ops->get_power_status(slot, &(info->power_status)); - slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); - slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); - slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); - - /* result = pci_hp_change_slot_info(buffer, info); */ - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree (info); - return result; -} - -static void interrupt_event_handler(struct controller *ctrl) -{ - int loop = 0; - int change = 1; - struct pci_func *func; - u8 hp_slot; - u8 getstatus; - struct slot *p_slot; - - while (change) { - change = 0; - - for (loop = 0; loop < 10; loop++) { - if (ctrl->event_queue[loop].event_type != 0) { - hp_slot = ctrl->event_queue[loop].hp_slot; - - func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot); - - if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { - dbg("button cancel\n"); - del_timer(&p_slot->task_event); - - switch (p_slot->state) { - case BLINKINGOFF_STATE: - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - if (PWR_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - break; - case BLINKINGON_STATE: - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - if (PWR_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)){ - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - break; - default: - warn("Not a valid state\n"); - return; - } - info(msg_button_cancel, p_slot->number); - p_slot->state = STATIC_STATE; - } - /* ***********Button Pressed (No action on 1st press...) */ - else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { - - if (ATTN_BUTTN(ctrl->ctrlcap)) { - dbg("Button pressed\n"); - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { - /* slot is on */ - dbg("slot is on\n"); - p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); - } else { - /* slot is off */ - dbg("slot is off\n"); - p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); - } - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - if (ATTN_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - init_timer(&p_slot->task_event); - p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ - p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; - p_slot->task_event.data = (unsigned long) p_slot; - - dbg("add_timer p_slot = %p\n", (void *) p_slot); - add_timer(&p_slot->task_event); - } - } - /***********POWER FAULT********************/ - else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { - if (POWER_CTRL(ctrl->ctrlcap)) { - dbg("power fault\n"); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - if (ATTN_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->set_attention_status(p_slot, 1); - wait_for_ctrl_irq (ctrl); - } - - if (PWR_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->green_led_off(p_slot); - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - } - } - /***********SURPRISE REMOVAL********************/ - else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || - (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { - if (HP_SUPR_RM(ctrl->ctrlcap)) { - dbg("Surprise Removal\n"); - if (p_slot) { - surprise_rm_pending = (unsigned long) p_slot; - up(&event_semaphore); - update_slot_info(p_slot); - } - } - } else { - /* refresh notification */ - if (p_slot) - update_slot_info(p_slot); - } - - ctrl->event_queue[loop].event_type = 0; - - change = 1; - } - } /* End of FOR loop */ - } + kfree(info); } - +/* + * Note: This function must be called with slot->hotplug_lock held + */ int pciehp_enable_slot(struct slot *p_slot) { u8 getstatus = 0; int rc; - struct pci_func *func; - - func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); - if (!func) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); - return 1; - } + struct controller *ctrl = p_slot->ctrl; - /* Check to see if (latch closed, card present, power off) */ - down(&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); - up(&p_slot->ctrl->crit_sect); - return 1; + pciehp_get_adapter_status(p_slot, &getstatus); + if (!getstatus) { + ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); + return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { - 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); - up(&p_slot->ctrl->crit_sect); - return 1; + if (MRL_SENS(p_slot->ctrl)) { + pciehp_get_latch_status(p_slot, &getstatus); + if (getstatus) { + ctrl_info(ctrl, "Latch open on slot(%s)\n", + slot_name(p_slot)); + return -ENODEV; } } - - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { - 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); - up(&p_slot->ctrl->crit_sect); - return 1; + + if (POWER_CTRL(p_slot->ctrl)) { + pciehp_get_power_status(p_slot, &getstatus); + if (getstatus) { + ctrl_info(ctrl, "Already enabled on slot(%s)\n", + slot_name(p_slot)); + return -EINVAL; } } - up(&p_slot->ctrl->crit_sect); - slot_remove(func); + pciehp_get_latch_status(p_slot, &getstatus); - func = pciehp_slot_create(p_slot->bus); - if (func == NULL) - return 1; - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; - - rc = board_added(func, p_slot->ctrl); - if (rc) { - if (is_bridge(func)) - bridge_slot_remove(func); - else - slot_remove(func); - - /* Setup slot structure with entry for empty slot */ - func = pciehp_slot_create(p_slot->bus); - if (func == NULL) - return 1; /* Out of memory */ - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; - } - - if (p_slot) - update_slot_info(p_slot); + rc = board_added(p_slot); + if (rc) + pciehp_get_latch_status(p_slot, &getstatus); return rc; } - +/* + * Note: This function must be called with slot->hotplug_lock held + */ int pciehp_disable_slot(struct slot *p_slot) { - u8 class_code, header_type, BCR; - u8 index = 0; u8 getstatus = 0; - u32 rc = 0; - int ret = 0; - unsigned int devfn; - struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; - struct pci_func *func; + struct controller *ctrl = p_slot->ctrl; if (!p_slot->ctrl) return 1; - /* Check to see if (latch closed, card present, power on) */ - down(&p_slot->ctrl->crit_sect); - - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { - ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; - } - } - - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { - ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (ret || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; - } - } - - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { - ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (POWER_CTRL(p_slot->ctrl)) { + pciehp_get_power_status(p_slot, &getstatus); + if (!getstatus) { + ctrl_info(ctrl, "Already disabled on slot(%s)\n", + slot_name(p_slot)); + return -EINVAL; } } - up(&p_slot->ctrl->crit_sect); - - func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); - - /* Make sure there are no video controllers here - * for all func of p_slot - */ - while (func && !rc) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check the Class Code */ - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (rc) - return rc; - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - /* Display/Video adapter (not supported) */ - rc = REMOVE_NOT_SUPPORTED; - } else { - /* See if it's a bridge */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - /* If it's a bridge, check the VGA Enable bit */ - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); - if (rc) - return rc; - - /* If the VGA Enable bit is set, remove isn't supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { - rc = REMOVE_NOT_SUPPORTED; - } - } - } - - func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); - } - - func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); - if ((func != NULL) && !rc) { - rc = remove_board(func, p_slot->ctrl); - } else if (!rc) - rc = 1; - - if (p_slot) - update_slot_info(p_slot); - - return rc; + return remove_board(p_slot); } - -/** - * configure_new_device - Configures the PCI header information of one board. - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Returns 0 if success - * - */ -static u32 configure_new_device(struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) +int pciehp_sysfs_enable_slot(struct slot *p_slot) { - u8 temp_byte, function, max_functions, stop_it; - int rc; - u32 ID; - struct pci_func *new_slot; - struct pci_bus lpci_bus, *pci_bus; - int index; - - new_slot = func; - - dbg("%s\n", __FUNCTION__); - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - - /* Check for Multi-function device */ - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - return rc; - } - - if (temp_byte & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - rc = configure_new_function(ctrl, new_slot, behind_bridge, - resources, bridge_bus, bridge_dev); - - if (rc) { - dbg("configure_new_function failed: %d\n", rc); - index = 0; - - while (new_slot) { - new_slot = pciehp_slot_find(new_slot->bus, - new_slot->device, index++); + int retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; - if (new_slot) - pciehp_return_board_resources(new_slot, - resources); - } - - return rc; - } - - function++; - - stop_it = 0; - - /* The following loop skips to the next present function - * and creates a board structure - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ - function++; - } else { /* There's something there */ - /* Setup slot structure. */ - new_slot = pciehp_slot_create(func->bus); - - if (new_slot == NULL) { - /* Out of memory */ - return 1; - } - - new_slot->bus = func->bus; - new_slot->device = func->device; - new_slot->function = function; - new_slot->is_a_board = 1; - new_slot->status = 0; - - stop_it++; - } - } - - } while (function < max_functions); - dbg("returning from %s\n", __FUNCTION__); - - return 0; -} - -/* - * Configuration logic that involves the hotplug data structures and - * their bookkeeping - */ - -/** - * configure_bridge: fill bridge's registers, either configure or disable it. - */ -static int -configure_bridge(struct pci_bus *pci_bus, unsigned int devfn, - struct pci_resource *mem_node, - struct pci_resource **hold_mem_node, - int base_addr, int limit_addr) -{ - u16 temp_word; - u32 rc; - - if (mem_node) { - memcpy(*hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; - - /* set Mem base and Limit registers */ - RES_CHECK(mem_node->base, 16); - temp_word = (u16)(mem_node->base >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word); - - RES_CHECK(mem_node->base + mem_node->length - 1, 16); - temp_word = (u16)((mem_node->base + mem_node->length - 1) >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word); - - kfree(*hold_mem_node); - *hold_mem_node = NULL; - } - return rc; -} - -static int -configure_new_bridge(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, - struct pci_bus *pci_bus) -{ - int cloop; - u8 temp_byte; - u8 device; - u16 temp_word; - u32 rc; - u32 ID; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_resource *hold_mem_node; - struct pci_resource *hold_p_mem_node; - struct pci_resource *hold_IO_node; - struct pci_resource *hold_bus_node; - struct irq_mapping irqs; - struct pci_func *new_slot; - struct resource_lists temp_resources; - - devfn = PCI_DEVFN(func->device, func->function); - - /* set Primary bus */ - dbg("set Primary bus = 0x%x\n", func->bus); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); - if (rc) - return rc; - - /* find range of busses to use */ - bus_node = get_max_resource(&resources->bus_head, 1L); - - /* If we don't have any busses to allocate, we can't continue */ - if (!bus_node) { - err("Got NO bus resource to use\n"); - return -ENOMEM; - } - dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); - - /* set Secondary bus */ - temp_byte = (u8)bus_node->base; - dbg("set Secondary bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); - if (rc) - return rc; - - /* set subordinate bus */ - temp_byte = (u8)(bus_node->base + bus_node->length - 1); - dbg("set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - if (rc) - return rc; - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - if (rc) - return rc; - - /* Setup the IO, memory, and prefetchable windows */ - - io_node = get_max_resource(&(resources->io_head), 0x1000L); - if (io_node) { - dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, - io_node->length, io_node->next); - } - - mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - if (mem_node) { - dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, - mem_node->length, mem_node->next); - } - - if (resources->p_mem_head) - p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); - else { - /* - * In some platform implementation, MEM and PMEM are not - * distinguished, and hence ACPI _CRS has only MEM entries - * for both MEM and PMEM. - */ - dbg("using MEM for PMEM\n"); - p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - } - if (p_mem_node) { - dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, - p_mem_node->length, p_mem_node->next); - } - - /* set up the IRQ info */ - if (!resources->irqs) { - irqs.barber_pole = 0; - irqs.interrupt[0] = 0; - irqs.interrupt[1] = 0; - irqs.interrupt[2] = 0; - irqs.interrupt[3] = 0; - irqs.valid_INT = 0; - } else { - irqs.barber_pole = resources->irqs->barber_pole; - irqs.interrupt[0] = resources->irqs->interrupt[0]; - irqs.interrupt[1] = resources->irqs->interrupt[1]; - irqs.interrupt[2] = resources->irqs->interrupt[2]; - irqs.interrupt[3] = resources->irqs->interrupt[3]; - irqs.valid_INT = resources->irqs->valid_INT; - } - - /* set up resource lists that are now aligned on top and bottom - * for anything behind the bridge. - */ - temp_resources.bus_head = bus_node; - temp_resources.io_head = io_node; - temp_resources.mem_head = mem_node; - temp_resources.p_mem_head = p_mem_node; - temp_resources.irqs = &irqs; - - /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources - */ - hold_bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_IO_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { - kfree(hold_bus_node); - kfree(hold_IO_node); - kfree(hold_mem_node); - kfree(hold_p_mem_node); - - return 1; - } - - memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); - - bus_node->base += 1; - bus_node->length -= 1; - bus_node->next = NULL; - - /* If we have IO resources copy them and fill in the bridge's - * IO range registers - */ - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - /* set IO base and Limit registers */ - RES_CHECK(io_node->base, 8); - temp_byte = (u8)(io_node->base >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - RES_CHECK(io_node->base + io_node->length - 1, 8); - temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } - - /* If we have memory resources copy them and fill in the bridge's - * memory range registers. Otherwise, fill in the range - * registers with values that disable them. - */ - rc = configure_bridge(pci_bus, devfn, mem_node, &hold_mem_node, - PCI_MEMORY_BASE, PCI_MEMORY_LIMIT); - - /* If we have prefetchable memory resources copy them and - * fill in the bridge's memory range registers. Otherwise, - * fill in the range registers with values that disable them. - */ - rc = configure_bridge(pci_bus, devfn, p_mem_node, &hold_p_mem_node, - PCI_PREF_MEMORY_BASE, PCI_PREF_MEMORY_LIMIT); - - /* Adjust this to compensate for extra adjustment in first loop */ - irqs.barber_pole--; - - rc = 0; - - /* Here we actually find the devices and configure them */ - for (device = 0; (device <= 0x1F) && !rc; device++) { - irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; - - ID = 0xFFFFFFFF; - pci_bus->number = hold_bus_node->base; - pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - pci_bus->number = func->bus; - - if (ID != 0xFFFFFFFF) { /* device Present */ - /* Setup slot structure. */ - new_slot = pciehp_slot_create(hold_bus_node->base); - - if (new_slot == NULL) { - /* Out of memory */ - rc = -ENOMEM; - continue; - } - - new_slot->bus = hold_bus_node->base; - new_slot->device = device; - new_slot->function = 0; - new_slot->is_a_board = 1; - new_slot->status = 0; - - rc = configure_new_device(ctrl, new_slot, 1, - &temp_resources, func->bus, - func->device); - dbg("configure_new_device rc=0x%x\n",rc); - } /* End of IF (device in slot?) */ - } /* End of FOR loop */ - - if (rc) { - pciehp_destroy_resource_list(&temp_resources); - - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return(rc); - } - - /* save the interrupt routing information */ - if (resources->irqs) { - resources->irqs->interrupt[0] = irqs.interrupt[0]; - resources->irqs->interrupt[1] = irqs.interrupt[1]; - resources->irqs->interrupt[2] = irqs.interrupt[2]; - resources->irqs->interrupt[3] = irqs.interrupt[3]; - resources->irqs->valid_INT = irqs.valid_INT; - } else if (!behind_bridge) { - /* We need to hook up the interrupts here */ - for (cloop = 0; cloop < 4; cloop++) { - if (irqs.valid_INT & (0x01 << cloop)) { - rc = pciehp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); - if (rc) { - pciehp_destroy_resource_list (&temp_resources); - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return rc; - } - } - } /* end of for loop */ - } - - /* Return unused bus resources - * First use the temporary node to store information for the board - */ - if (hold_bus_node && bus_node && temp_resources.bus_head) { - hold_bus_node->length = bus_node->base - hold_bus_node->base; - - hold_bus_node->next = func->bus_head; - func->bus_head = hold_bus_node; - - temp_byte = (u8)(temp_resources.bus_head->base - 1); - - /* set subordinate bus */ - dbg("re-set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - - if (temp_resources.bus_head->length == 0) { - kfree(temp_resources.bus_head); - temp_resources.bus_head = NULL; - } else { - dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", - func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); - return_resource(&(resources->bus_head), temp_resources.bus_head); - } - } - - /* If we have IO space available and there is some left, - * return the unused portion - */ - if (hold_IO_node && temp_resources.io_head) { - io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), - &hold_IO_node, 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - hold_IO_node->base = io_node->base + io_node->length; - - RES_CHECK(hold_IO_node->base, 8); - temp_byte = (u8)((hold_IO_node->base) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - return_resource(&(resources->io_head), io_node); - } - - io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - /* First use the temporary node to store information for the board */ - hold_IO_node->length = io_node->base - hold_IO_node->base; - - /* If we used any, add it to the board's list */ - if (hold_IO_node->length) { - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - - RES_CHECK(io_node->base - 1, 8); - temp_byte = (u8)((io_node->base - 1) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - } else { - /* it doesn't need any IO */ - temp_byte = 0x00; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - kfree(hold_IO_node); - } - } else { - /* it used most of the range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - } else if (hold_IO_node) { - /* it used the whole range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - - /* If we have memory space available and there is some left, - * return the unused portion - */ - if (hold_mem_node && temp_resources.mem_head) { - mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - hold_mem_node->base = mem_node->base + mem_node->length; - - RES_CHECK(hold_mem_node->base, 16); - temp_word = (u16)((hold_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - return_resource(&(resources->mem_head), mem_node); - } - - mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - /* First use the temporary node to store information for the board */ - hold_mem_node->length = mem_node->base - hold_mem_node->base; - - if (hold_mem_node->length) { - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - - /* configure end address */ - RES_CHECK(mem_node->base - 1, 16); - temp_word = (u16)((mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - /* Return unused resources to the pool */ - return_resource(&(resources->mem_head), mem_node); - } else { - /* it doesn't need any Mem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->mem_head), mem_node); - kfree(hold_mem_node); - } - } else { - /* it used most of the range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - } else if (hold_mem_node) { - /* it used the whole range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - - /* If we have prefetchable memory space available and there is some - * left at the end, return the unused portion - */ - if (hold_p_mem_node && temp_resources.p_mem_head) { - p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), - &hold_p_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; - - RES_CHECK(hold_p_mem_node->base, 16); - temp_word = (u16)((hold_p_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } - - p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - /* First use the temporary node to store information for the board */ - hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; - - /* If we used any, add it to the board's list */ - if (hold_p_mem_node->length) { - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - - RES_CHECK(p_mem_node->base - 1, 16); - temp_word = (u16)((p_mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } else { - /* it doesn't need any PMem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - kfree(hold_p_mem_node); - } - } else { - /* it used the most of the range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - } else if (hold_p_mem_node) { - /* it used the whole range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGON_STATE: + cancel_delayed_work(&p_slot->work); + case STATIC_STATE: + p_slot->state = POWERON_STATE; + mutex_unlock(&p_slot->lock); + mutex_lock(&p_slot->hotplug_lock); + retval = pciehp_enable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + break; + case POWERON_STATE: + ctrl_info(ctrl, "Slot %s is already in powering on state\n", + slot_name(p_slot)); + break; + case BLINKINGOFF_STATE: + case POWEROFF_STATE: + ctrl_info(ctrl, "Already enabled on slot %s\n", + slot_name(p_slot)); + break; + default: + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); + break; } + mutex_unlock(&p_slot->lock); - /* We should be configuring an IRQ and the bridge's base address - * registers if it needs them. Although we have never seen such - * a device - */ - - pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - - dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - - return rc; + return retval; } -/** - * configure_new_function - Configures the PCI header information of one device - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Calls itself recursively for bridged devices. - * Returns 0 if success - * - */ -static int -configure_new_function(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, - u8 bridge_bus, u8 bridge_dev) +int pciehp_sysfs_disable_slot(struct slot *p_slot) { - int cloop; - u8 temp_byte; - u8 class_code; - u32 rc; - u32 temp_register; - u32 base; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *io_node; - struct pci_bus lpci_bus, *pci_bus; - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check for Bridge */ - rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); - if (rc) - return rc; - dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__, - func->bus, func->device, func->function, temp_byte); - - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - rc = configure_new_bridge(ctrl, func, behind_bridge, resources, - pci_bus); - - if (rc) - return rc; - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - /* Standard device */ - u64 base64; - rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_DISPLAY) - return DEVICE_TYPE_NOT_SUPPORTED; - - /* Figure out IO and memory needs */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - temp_register = 0xFFFFFFFF; - - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, - func->bus, func->device, func->function); - - if (!temp_register) - continue; - - base64 = 0L; - if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { - /* Map IO */ - - /* set base = amount of IO space */ - base = temp_register & 0xFFFFFFFC; - base = ~base + 1; - - dbg("NEED IO length(0x%x)\n", base); - io_node = get_io_resource(&(resources->io_head),(ulong)base); - - /* allocate the resource to the board */ - if (io_node) { - dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); - base = (u32)io_node->base; - io_node->next = func->io_head; - func->io_head = io_node; - } else { - err("Got NO IO resource(length=0x%x)\n", base); - return -ENOMEM; - } - } else { /* map MEM */ - int prefetchable = 1; - struct pci_resource **res_node = &func->p_mem_head; - char *res_type_str = "PMEM"; - u32 temp_register2; - - if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { - prefetchable = 0; - res_node = &func->mem_head; - res_type_str++; - } - - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node=get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node = get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base = (u32)mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, - mem_node->length); - } else { - err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, - temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node = get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node = get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base64 = mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), - (u32)base64, mem_node->length); - } else { - err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - default: - dbg("reserved BAR type=0x%x\n", temp_register); - break; - } - - } - - if (base64) { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - cloop += 4; - base64 >>= 32; - - if (base64) { - dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); - base64 = 0x0L; - } - - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - } else { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); - } - } /* End of base register loop */ - - /* disable ROM base Address */ - rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); - if (rc) - return rc; - - pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); - - dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, - func->function); - } /* End of Not-A-Bridge else */ - else { - /* It's some strange type of PCI adapter (Cardbus?) */ - return DEVICE_TYPE_NOT_SUPPORTED; - } + int retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; - func->configured = 1; + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGOFF_STATE: + cancel_delayed_work(&p_slot->work); + case STATIC_STATE: + p_slot->state = POWEROFF_STATE; + mutex_unlock(&p_slot->lock); + retval = pciehp_disable_slot(p_slot); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + break; + case POWEROFF_STATE: + ctrl_info(ctrl, "Slot %s is already in powering off state\n", + slot_name(p_slot)); + break; + case BLINKINGON_STATE: + case POWERON_STATE: + ctrl_info(ctrl, "Already disabled on slot %s\n", + slot_name(p_slot)); + break; + default: + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); + break; + } + mutex_unlock(&p_slot->lock); - return 0; + return retval; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7a0e27f0e06..42914e04d11 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -27,1477 +27,803 @@ * */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> +#include <linux/signal.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include <linux/pci.h> -#include <asm/system.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/slab.h> + #include "../pci.h" #include "pciehp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ - -struct ctrl_reg { - u8 cap_id; - u8 nxt_ptr; - u16 cap_reg; - u32 dev_cap; - u16 dev_ctrl; - u16 dev_status; - u32 lnk_cap; - u16 lnk_ctrl; - u16 lnk_status; - u32 slot_cap; - u16 slot_ctrl; - u16 slot_status; - u16 root_ctrl; - u16 rsvp; - u32 root_status; -} __attribute__ ((packed)); - -/* offsets to the controller registers based on the above structure layout */ -enum ctrl_offsets { - PCIECAPID = offsetof(struct ctrl_reg, cap_id), - NXTCAPPTR = offsetof(struct ctrl_reg, nxt_ptr), - CAPREG = offsetof(struct ctrl_reg, cap_reg), - DEVCAP = offsetof(struct ctrl_reg, dev_cap), - DEVCTRL = offsetof(struct ctrl_reg, dev_ctrl), - DEVSTATUS = offsetof(struct ctrl_reg, dev_status), - LNKCAP = offsetof(struct ctrl_reg, lnk_cap), - LNKCTRL = offsetof(struct ctrl_reg, lnk_ctrl), - LNKSTATUS = offsetof(struct ctrl_reg, lnk_status), - SLOTCAP = offsetof(struct ctrl_reg, slot_cap), - SLOTCTRL = offsetof(struct ctrl_reg, slot_ctrl), - SLOTSTATUS = offsetof(struct ctrl_reg, slot_status), - ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl), - ROOTSTATUS = offsetof(struct ctrl_reg, root_status), -}; -static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ - -#define PCIE_CAP_ID(cb) ( cb + PCIECAPID ) -#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR ) -#define CAP_REG(cb) ( cb + CAPREG ) -#define DEV_CAP(cb) ( cb + DEVCAP ) -#define DEV_CTRL(cb) ( cb + DEVCTRL ) -#define DEV_STATUS(cb) ( cb + DEVSTATUS ) -#define LNK_CAP(cb) ( cb + LNKCAP ) -#define LNK_CTRL(cb) ( cb + LNKCTRL ) -#define LNK_STATUS(cb) ( cb + LNKSTATUS ) -#define SLOT_CAP(cb) ( cb + SLOTCAP ) -#define SLOT_CTRL(cb) ( cb + SLOTCTRL ) -#define SLOT_STATUS(cb) ( cb + SLOTSTATUS ) -#define ROOT_CTRL(cb) ( cb + ROOTCTRL ) -#define ROOT_STATUS(cb) ( cb + ROOTSTATUS ) - -#define hp_register_read_word(pdev, reg , value) \ - pci_read_config_word(pdev, reg, &value) - -#define hp_register_read_dword(pdev, reg , value) \ - pci_read_config_dword(pdev, reg, &value) - -#define hp_register_write_word(pdev, reg , value) \ - pci_write_config_word(pdev, reg, value) - -#define hp_register_dwrite_word(pdev, reg , value) \ - pci_write_config_dword(pdev, reg, value) - -/* Field definitions in PCI Express Capabilities Register */ -#define CAP_VER 0x000F -#define DEV_PORT_TYPE 0x00F0 -#define SLOT_IMPL 0x0100 -#define MSG_NUM 0x3E00 - -/* Device or Port Type */ -#define NAT_ENDPT 0x00 -#define LEG_ENDPT 0x01 -#define ROOT_PORT 0x04 -#define UP_STREAM 0x05 -#define DN_STREAM 0x06 -#define PCIE_PCI_BRDG 0x07 -#define PCI_PCIE_BRDG 0x10 - -/* Field definitions in Device Capabilities Register */ -#define DATTN_BUTTN_PRSN 0x1000 -#define DATTN_LED_PRSN 0x2000 -#define DPWR_LED_PRSN 0x4000 - -/* Field definitions in Link Capabilities Register */ -#define MAX_LNK_SPEED 0x000F -#define MAX_LNK_WIDTH 0x03F0 - -/* Link Width Encoding */ -#define LNK_X1 0x01 -#define LNK_X2 0x02 -#define LNK_X4 0x04 -#define LNK_X8 0x08 -#define LNK_X12 0x0C -#define LNK_X16 0x10 -#define LNK_X32 0x20 - -/*Field definitions of Link Status Register */ -#define LNK_SPEED 0x000F -#define NEG_LINK_WD 0x03F0 -#define LNK_TRN_ERR 0x0400 -#define LNK_TRN 0x0800 -#define SLOT_CLK_CONF 0x1000 - -/* Field definitions in Slot Capabilities Register */ -#define ATTN_BUTTN_PRSN 0x00000001 -#define PWR_CTRL_PRSN 0x00000002 -#define MRL_SENS_PRSN 0x00000004 -#define ATTN_LED_PRSN 0x00000008 -#define PWR_LED_PRSN 0x00000010 -#define HP_SUPR_RM_SUP 0x00000020 -#define HP_CAP 0x00000040 -#define SLOT_PWR_VALUE 0x000003F8 -#define SLOT_PWR_LIMIT 0x00000C00 -#define PSN 0xFFF80000 /* PSN: Physical Slot Number */ - -/* Field definitions in Slot Control Register */ -#define ATTN_BUTTN_ENABLE 0x0001 -#define PWR_FAULT_DETECT_ENABLE 0x0002 -#define MRL_DETECT_ENABLE 0x0004 -#define PRSN_DETECT_ENABLE 0x0008 -#define CMD_CMPL_INTR_ENABLE 0x0010 -#define HP_INTR_ENABLE 0x0020 -#define ATTN_LED_CTRL 0x00C0 -#define PWR_LED_CTRL 0x0300 -#define PWR_CTRL 0x0400 - -/* Attention indicator and Power indicator states */ -#define LED_ON 0x01 -#define LED_BLINK 0x10 -#define LED_OFF 0x11 - -/* Power Control Command */ -#define POWER_ON 0 -#define POWER_OFF 0x0400 - -/* Field definitions in Slot Status Register */ -#define ATTN_BUTTN_PRESSED 0x0001 -#define PWR_FAULT_DETECTED 0x0002 -#define MRL_SENS_CHANGED 0x0004 -#define PRSN_DETECT_CHANGED 0x0008 -#define CMD_COMPLETED 0x0010 -#define MRL_STATE 0x0020 -#define PRSN_STATE 0x0040 - -struct php_ctlr_state_s { - struct php_ctlr_state_s *pnext; - struct pci_dev *pci_dev; - unsigned int irq; - unsigned long flags; /* spinlock's */ - u32 slot_device_offset; - u32 num_slots; - struct timer_list int_poll_timer; /* Added for poll event */ - php_intr_callback_t attention_button_callback; - php_intr_callback_t switch_change_callback; - php_intr_callback_t presence_change_callback; - php_intr_callback_t power_fault_callback; - void *callback_instance_id; - struct ctrl_reg *creg; /* Ptr to controller register space */ -}; - - -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 sequence # */ -static spinlock_t list_lock; - -static irqreturn_t pcie_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); - -/* This is the interrupt polling timeout function. */ -static void int_poll_timeout(unsigned long lphp_ctlr) +static inline struct pci_dev *ctrl_dev(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + return ctrl->pcie->port; +} - DBG_ENTER_ROUTINE +static irqreturn_t pcie_isr(int irq, void *dev_id); +static void start_int_poll_timer(struct controller *ctrl, int sec); - if ( !php_ctlr ) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } +/* This is the interrupt polling timeout function. */ +static void int_poll_timeout(unsigned long data) +{ + struct controller *ctrl = (struct controller *)data; /* Poll for interrupt events. regs == NULL => polling */ - pcie_isr( 0, (void *)php_ctlr, NULL ); - - init_timer(&php_ctlr->int_poll_timer); + pcie_isr(0, ctrl); + init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) - pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + pciehp_poll_time = 2; /* default polling interval is 2 sec */ - start_int_poll_timer(php_ctlr, pciehp_poll_time); - - return; + start_int_poll_timer(ctrl, pciehp_poll_time); } /* This function starts the interrupt polling timer. */ -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +static void start_int_poll_timer(struct controller *ctrl, 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; + + ctrl->poll_timer.function = &int_poll_timeout; + ctrl->poll_timer.data = (unsigned long)ctrl; + ctrl->poll_timer.expires = jiffies + sec * HZ; + add_timer(&ctrl->poll_timer); } -static int pcie_write_cmd(struct slot *slot, u16 cmd) +static inline int pciehp_request_irq(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - int retval = 0; - u16 slot_status; - - DBG_ENTER_ROUTINE - - dbg("%s : Enter\n", __FUNCTION__); - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } - dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status); - - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { - /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue - the next command according to spec. Just print out the error message */ - dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__); - } + int retval, irq = ctrl->pcie->irq; - dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd); - retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE); - if (retval) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; + /* Install interrupt polling timer. Start with 10 sec delay */ + if (pciehp_poll_mode) { + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); + return 0; } - dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd | CMD_CMPL_INTR_ENABLE); - dbg("%s : Exit\n", __FUNCTION__); - DBG_LEAVE_ROUTINE + /* Installs the interrupt handler */ + retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); + if (retval) + ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", + irq); return retval; } -static int hpc_check_lnk_status(struct controller *ctrl) +static inline void pciehp_free_irq(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - u16 lnk_status; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status); + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); + else + free_irq(ctrl->pcie->irq, ctrl); +} - if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); - return retval; +static int pcie_poll_cmd(struct controller *ctrl) +{ + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 slot_status; + int timeout = 1000; + + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + if (slot_status & PCI_EXP_SLTSTA_CC) { + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_CC); + return 1; + } + while (timeout > 0) { + msleep(10); + timeout -= 10; + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + if (slot_status & PCI_EXP_SLTSTA_CC) { + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_CC); + return 1; + } } + return 0; /* timeout */ +} - dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status); - if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || - !(lnk_status & NEG_LINK_WD)) { - err("%s : Link Training Error occurs \n", __FUNCTION__); - retval = -1; - return retval; - } +static void pcie_wait_cmd(struct controller *ctrl, int poll) +{ + unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; + unsigned long timeout = msecs_to_jiffies(msecs); + int rc; - DBG_LEAVE_ROUTINE - return retval; + if (poll) + rc = pcie_poll_cmd(ctrl); + else + rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); + if (!rc) + ctrl_dbg(ctrl, "Command not completed in 1000 msec\n"); } - -static int hpc_get_attention_status(struct slot *slot, u8 *status) +/** + * pcie_write_cmd - Issue controller command + * @ctrl: controller to which the command is issued + * @cmd: command value written to slot control register + * @mask: bitmask of slot control register to be modified + */ +static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 slot_status; u16 slot_ctrl; - u8 atten_led_state; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - - if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; + mutex_lock(&ctrl->ctrl_lock); + + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + if (slot_status & PCI_EXP_SLTSTA_CC) { + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_CC); + if (!ctrl->no_cmd_complete) { + /* + * After 1 sec and CMD_COMPLETED still not set, just + * proceed forward to issue the next command according + * to spec. Just print out the error message. + */ + ctrl_dbg(ctrl, "CMD_COMPLETED not clear after 1 sec\n"); + } else if (!NO_CMD_CMPL(ctrl)) { + /* + * This controller seems to notify of command completed + * event even though it supports none of power + * controller, attention led, power led and EMI. + */ + ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to wait for command completed event\n"); + ctrl->no_cmd_complete = 0; + } else { + ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe the controller is broken\n"); + } } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - - atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; - - switch (atten_led_state) { - case 0: - *status = 0xFF; /* Reserved */ - break; - case 1: - *status = 1; /* On */ - break; - case 2: - *status = 2; /* Blink */ - break; - case 3: - *status = 0; /* Off */ - break; - default: - *status = 0xFF; - break; + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + slot_ctrl &= ~mask; + slot_ctrl |= (cmd & mask); + ctrl->cmd_busy = 1; + smp_mb(); + pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); + + /* + * Wait for command completion. + */ + if (!ctrl->no_cmd_complete) { + int poll = 0; + /* + * if hotplug interrupt is not enabled or command + * completed interrupt is not enabled, we need to poll + * command completed event. + */ + if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) || + !(slot_ctrl & PCI_EXP_SLTCTL_CCIE)) + poll = 1; + pcie_wait_cmd(ctrl, poll); } - - DBG_LEAVE_ROUTINE - return 0; + mutex_unlock(&ctrl->ctrl_lock); } -static int hpc_get_power_status(struct slot * slot, u8 *status) +bool pciehp_check_link_active(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_ctrl; - u8 pwr_state; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 lnk_status; + bool ret; - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); + ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); - if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; - } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + if (ret) + ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); - pwr_state = (slot_ctrl & PWR_CTRL) >> 10; + return ret; +} - switch (pwr_state) { - case 0: - *status = 1; - break; - case 1: - *status = 0; - break; - default: - *status = 0xFF; - break; - } +static void __pcie_wait_link_active(struct controller *ctrl, bool active) +{ + int timeout = 1000; - DBG_LEAVE_ROUTINE - return retval; + if (pciehp_check_link_active(ctrl) == active) + return; + while (timeout > 0) { + msleep(10); + timeout -= 10; + if (pciehp_check_link_active(ctrl) == active) + return; + } + ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n", + active ? "set" : "cleared"); } - -static int hpc_get_latch_status(struct slot *slot, u8 *status) +static void pcie_wait_link_active(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_status; - int retval = 0; + __pcie_wait_link_active(ctrl, true); +} - DBG_ENTER_ROUTINE +static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) +{ + u32 l; + int count = 0; + int delay = 1000, step = 20; + bool found = false; - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + do { + found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0); + count++; - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); + if (found) + break; - if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } + msleep(step); + delay -= step; + } while (delay > 0); - *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; + if (count > 1 && pciehp_debug) + printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", + pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), count, step, l); - DBG_LEAVE_ROUTINE - return 0; + return found; } -static int hpc_get_adapter_status(struct slot *slot, u8 *status) +int pciehp_check_link_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_status; - u8 card_state; - int retval = 0; - - DBG_ENTER_ROUTINE + struct pci_dev *pdev = ctrl_dev(ctrl); + bool found; + u16 lnk_status; - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + /* + * Data Link Layer Link Active Reporting must be capable for + * hot-plug capable downstream port. But old controller might + * not implement it. In this case, we wait for 1000 ms. + */ + if (ctrl->link_active_reporting) + pcie_wait_link_active(ctrl); + else + msleep(1000); + + /* wait 100ms before read pci conf, and try in 1s */ + msleep(100); + found = pci_bus_check_dev(ctrl->pcie->port->subordinate, + PCI_DEVFN(0, 0)); + + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); + ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); + if ((lnk_status & PCI_EXP_LNKSTA_LT) || + !(lnk_status & PCI_EXP_LNKSTA_NLW)) { + ctrl_err(ctrl, "Link Training Error occurs\n"); return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); + pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); - if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } - card_state = (u8)((slot_status & PRSN_STATE) >> 6); - *status = (card_state == 1) ? 1 : 0; + if (!found) + return -1; - DBG_LEAVE_ROUTINE return 0; } -static int hpc_query_power_fault(struct slot * slot) +static int __pciehp_link_set(struct controller *ctrl, bool enable) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_status; - u8 pwr_fault; - int retval = 0; - u8 status; + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 lnk_ctrl; - DBG_ENTER_ROUTINE + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + if (enable) + lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; + else + lnk_ctrl |= PCI_EXP_LNKCTL_LD; - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); + pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); + ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); + return 0; +} - if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } - pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - status = (pwr_fault != 1) ? 1 : 0; - - DBG_LEAVE_ROUTINE - /* Note: Logic 0 => fault */ - return status; +static int pciehp_link_enable(struct controller *ctrl) +{ + return __pciehp_link_set(ctrl, true); } -static int hpc_set_attention_status(struct slot *slot, u8 value) +void pciehp_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_cmd = 0; + struct controller *ctrl = slot->ctrl; + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; - int rc = 0; - dbg("%s: \n", __FUNCTION__); - if (!php_ctlr) { - 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; - } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return rc; - } - dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); - - switch (value) { - case 0 : /* turn off */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0; - break; - case 1: /* turn on */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; - break; - case 2: /* turn blink */ - slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; - break; - default: - return -1; + switch (slot_ctrl & PCI_EXP_SLTCTL_AIC) { + case PCI_EXP_SLTCTL_ATTN_IND_ON: + *status = 1; /* On */ + break; + case PCI_EXP_SLTCTL_ATTN_IND_BLINK: + *status = 2; /* Blink */ + break; + case PCI_EXP_SLTCTL_ATTN_IND_OFF: + *status = 0; /* Off */ + break; + default: + *status = 0xFF; + break; } - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - - pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); - - return rc; } - -static void hpc_set_green_led_on(struct slot *slot) +void pciehp_get_power_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_cmd; + struct controller *ctrl = slot->ctrl; + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; - int rc = 0; - - dbg("%s: \n", __FUNCTION__); - if (!php_ctlr) { - 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 ; - } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return; + switch (slot_ctrl & PCI_EXP_SLTCTL_PCC) { + case PCI_EXP_SLTCTL_PWR_ON: + *status = 1; /* On */ + break; + case PCI_EXP_SLTCTL_PWR_OFF: + *status = 0; /* Off */ + break; + default: + *status = 0xFF; + break; } - dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - - pcie_write_cmd(slot, slot_cmd); - - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); - return; } -static void hpc_set_green_led_off(struct slot *slot) +void pciehp_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_cmd; - u16 slot_ctrl; - int rc = 0; - - dbg("%s: \n", __FUNCTION__); - if (!php_ctlr) { - 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 ; - } + struct pci_dev *pdev = ctrl_dev(slot->ctrl); + u16 slot_status; - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); +} - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return; - } - dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); +void pciehp_get_adapter_status(struct slot *slot, u8 *status) +{ + struct pci_dev *pdev = ctrl_dev(slot->ctrl); + u16 slot_status; - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); +} - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); +int pciehp_query_power_fault(struct slot *slot) +{ + struct pci_dev *pdev = ctrl_dev(slot->ctrl); + u16 slot_status; - return; + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + return !!(slot_status & PCI_EXP_SLTSTA_PFD); } -static void hpc_set_green_led_blink(struct slot *slot) +void pciehp_set_attention_status(struct slot *slot, u8 value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; - u16 slot_ctrl; - int rc = 0; - - dbg("%s: \n", __FUNCTION__); - if (!php_ctlr) { - 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 ; - } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + if (!ATTN_LED(ctrl)) + return; - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + switch (value) { + case 0: /* turn off */ + slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF; + break; + case 1: /* turn on */ + slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON; + break; + case 2: /* turn blink */ + slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK; + break; + default: return; } - dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); - - slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; - - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - pcie_write_cmd(slot, slot_cmd); - - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); - return; + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); + pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); } -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */ - int *first_device_num, /* PCI dev num of the first slot in this PCIE */ - int *physical_slot_num, /* phy slot num of the first slot in this PCIE */ - u8 *ctrlcap) +void pciehp_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - u32 slot_cap; - int rc = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + struct controller *ctrl = slot->ctrl; - *first_device_num = 0; - *num_ctlr_slots = 1; - - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); - - if (rc) { - err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); - return -1; - } - - *physical_slot_num = slot_cap >> 19; - dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num); - - *ctrlcap = slot_cap & 0x0000007f; + if (!PWR_LED(ctrl)) + return; - DBG_LEAVE_ROUTINE - return 0; + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_ON); } -static void hpc_release_ctlr(struct controller *ctrl) +void pciehp_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - struct php_ctlr_state_s *p, *p_prev; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } + struct controller *ctrl = slot->ctrl; - if (pciehp_poll_mode) { - del_timer(&php_ctlr->int_poll_timer); - } else { - if (php_ctlr->irq) { - free_irq(php_ctlr->irq, ctrl); - php_ctlr->irq = 0; - if (!pcie_mch_quirk) - pci_disable_msi(php_ctlr->pci_dev); - } - } - if (php_ctlr->pci_dev) - php_ctlr->pci_dev = NULL; - - spin_lock(&list_lock); - p = php_ctlr_list_head; - p_prev = NULL; - while (p) { - if (p == php_ctlr) { - if (p_prev) - p_prev->pnext = p->pnext; - else - php_ctlr_list_head = p->pnext; - break; - } else { - p_prev = p; - p = p->pnext; - } - } - spin_unlock(&list_lock); - - kfree(php_ctlr); + if (!PWR_LED(ctrl)) + return; - DBG_LEAVE_ROUTINE - + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_OFF); } -static int hpc_power_on_slot(struct slot * slot) +void pciehp_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_cmd; - u16 slot_ctrl; - - int retval = 0; + struct controller *ctrl = slot->ctrl; - DBG_ENTER_ROUTINE - dbg("%s: \n", __FUNCTION__); - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - - if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; - } - dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), - slot_ctrl); + if (!PWR_LED(ctrl)) + return; - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_BLINK); +} - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; +int pciehp_power_on_slot(struct slot *slot) +{ + struct controller *ctrl = slot->ctrl; + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 slot_status; + int retval; - retval = pcie_write_cmd(slot, slot_cmd); + /* Clear sticky power-fault bit from previous power failures */ + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + if (slot_status & PCI_EXP_SLTSTA_PFD) + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PFD); + ctrl->power_fault_detected = 0; - if (retval) { - err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); - return -1; - } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_ON); - DBG_LEAVE_ROUTINE + retval = pciehp_link_enable(ctrl); + if (retval) + ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__); return retval; } -static int hpc_power_off_slot(struct slot * slot) +void pciehp_power_off_slot(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 slot_cmd; - u16 slot_ctrl; - - int retval = 0; + struct controller *ctrl = slot->ctrl; - DBG_ENTER_ROUTINE - dbg("%s: \n", __FUNCTION__); - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - slot->hp_slot = 0; - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - - if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; - } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), - slot_ctrl); - - slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; - - if (!pciehp_poll_mode) - slot_cmd = slot_cmd | HP_INTR_ENABLE; - - retval = pcie_write_cmd(slot, slot_cmd); - - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); - - DBG_LEAVE_ROUTINE - - return retval; + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_OFF); } -static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) +static irqreturn_t pcie_isr(int irq, void *dev_id) { - struct controller *ctrl = NULL; - struct php_ctlr_state_s *php_ctlr; - u8 schedule_flag = 0; - u16 slot_status, intr_detect, intr_loc; - u16 temp_word; - int hp_slot = 0; /* only 1 slot per PCI Express port */ - int rc = 0; - - if (!dev_id) - return IRQ_NONE; - - if (!pciehp_poll_mode) { - ctrl = dev_id; - php_ctlr = ctrl->hpc_ctlr_handle; - } else { - php_ctlr = dev_id; - ctrl = (struct controller *)php_ctlr->callback_instance_id; - } + struct controller *ctrl = (struct controller *)dev_id; + struct pci_dev *pdev = ctrl_dev(ctrl); + struct slot *slot = ctrl->slot; + u16 detected, intr_loc; + + /* + * In order to guarantee that all interrupt events are + * serviced, we need to re-inspect Slot Status register after + * clearing what is presumed to be the last pending interrupt. + */ + intr_loc = 0; + do { + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected); + + detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | + PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | + PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC); + detected &= ~intr_loc; + intr_loc |= detected; + if (!intr_loc) + return IRQ_NONE; + if (detected) + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + intr_loc); + } while (detected); - if (!ctrl) { - dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id); - return IRQ_NONE; - } - - if (!php_ctlr) { - dbg("%s: php_ctlr == NULL\n", __FUNCTION__); - return IRQ_NONE; - } + ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc); - 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__); - return IRQ_NONE; + /* Check Command Complete Interrupt Pending */ + if (intr_loc & PCI_EXP_SLTSTA_CC) { + ctrl->cmd_busy = 0; + smp_mb(); + wake_up(&ctrl->queue); } - intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | - PRSN_DETECT_CHANGED | CMD_COMPLETED ); - - intr_loc = slot_status & intr_detect; + if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) + return IRQ_HANDLED; - /* Check to see if it was our interrupt */ - if ( !intr_loc ) - return IRQ_NONE; + /* Check MRL Sensor Changed */ + if (intr_loc & PCI_EXP_SLTSTA_MRLSC) + pciehp_handle_switch_change(slot); - dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); - /* Mask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE; - } - - dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__); - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + /* Check Attention Button Pressed */ + if (intr_loc & PCI_EXP_SLTSTA_ABP) + pciehp_handle_attention_button(slot); - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); - if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE; - } - dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - - 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__); - return IRQ_NONE; - } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); - - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1f; - 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__); - return IRQ_NONE; - } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); - } - - if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending - */ - dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__); - wake_up_interruptible(&ctrl->queue); - } + /* Check Presence Detect Changed */ + if (intr_loc & PCI_EXP_SLTSTA_PDC) + pciehp_handle_presence_change(slot); - if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED)) - schedule_flag += php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED)) - schedule_flag += php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED)) - schedule_flag += php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED)) - schedule_flag += php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); - - /* Clear all events after serving them */ - temp_word = 0x1F; - 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__); - return IRQ_NONE; + /* Check Power Fault Detected */ + if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { + ctrl->power_fault_detected = 1; + pciehp_handle_power_fault(slot); } - /* Unmask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE; - } - dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__); - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; + if (intr_loc & PCI_EXP_SLTSTA_DLLSC) + pciehp_handle_linkstate_change(slot); - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); - if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return IRQ_NONE; - } - dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - - 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__); - return IRQ_NONE; - } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); - - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1F; - 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__); - return IRQ_NONE; - } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); - } - return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +void pcie_enable_notification(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pcie_link_speed lnk_speed; - u32 lnk_cap; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - 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; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - - if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); - return retval; - } + u16 cmd, mask; + + /* + * TBD: Power fault detected software notification support. + * + * Power fault detected software notification is not enabled + * now, because it caused power fault detected interrupt storm + * on some machines. On those machines, power fault detected + * bit in the slot status register was set again immediately + * when it is cleared in the interrupt service routine, and + * next power fault detected interrupt was notified again. + */ + + /* + * Always enable link events: thus link-up and link-down shall + * always be treated as hotplug and unplug respectively. Enable + * presence detect only if Attention Button is not present. + */ + cmd = PCI_EXP_SLTCTL_DLLSCE; + if (ATTN_BUTTN(ctrl)) + cmd |= PCI_EXP_SLTCTL_ABPE; + else + cmd |= PCI_EXP_SLTCTL_PDCE; + if (MRL_SENS(ctrl)) + cmd |= PCI_EXP_SLTCTL_MRLSCE; + if (!pciehp_poll_mode) + cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; - switch (lnk_cap & 0x000F) { - case 1: - lnk_speed = PCIE_2PT5GB; - break; - default: - lnk_speed = PCIE_LNK_SPEED_UNKNOWN; - break; - } + mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | + PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | + PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_DLLSCE); - *value = lnk_speed; - dbg("Max link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE - return retval; + pcie_write_cmd(ctrl, cmd, mask); } -static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) +static void pcie_disable_notification(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pcie_link_width lnk_wdth; - u32 lnk_cap; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - 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; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - - if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); - return retval; - } - - switch ((lnk_cap & 0x03F0) >> 4){ - case 0: - lnk_wdth = PCIE_LNK_WIDTH_RESRV; - break; - case 1: - lnk_wdth = PCIE_LNK_X1; - break; - case 2: - lnk_wdth = PCIE_LNK_X2; - break; - case 4: - lnk_wdth = PCIE_LNK_X4; - break; - case 8: - lnk_wdth = PCIE_LNK_X8; - break; - case 12: - lnk_wdth = PCIE_LNK_X12; - break; - case 16: - lnk_wdth = PCIE_LNK_X16; - break; - case 32: - lnk_wdth = PCIE_LNK_X32; - break; - default: - lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; - break; - } + u16 mask; - *value = lnk_wdth; - dbg("Max link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE - return retval; + mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | + PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | + PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_DLLSCE); + pcie_write_cmd(ctrl, 0, mask); } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +/* + * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary + * bus reset of the bridge, but at the same time we want to ensure that it is + * not seen as a hot-unplug, followed by the hot-plug of the device. Thus, + * disable link state notification and presence detection change notification + * momentarily, if we see that they could interfere. Also, clear any spurious + * events after. + */ +int pciehp_reset_slot(struct slot *slot, int probe) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; - int retval = 0; - u16 lnk_status; + struct controller *ctrl = slot->ctrl; + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 stat_mask = 0, ctrl_mask = 0; - DBG_ENTER_ROUTINE + if (probe) + return 0; - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; + if (!ATTN_BUTTN(ctrl)) { + ctrl_mask |= PCI_EXP_SLTCTL_PDCE; + stat_mask |= PCI_EXP_SLTSTA_PDC; } + ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE; + stat_mask |= PCI_EXP_SLTSTA_DLLSC; - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } + pcie_write_cmd(ctrl, 0, ctrl_mask); + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); + pci_reset_bridge_secondary_bus(ctrl->pcie->port); - if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); - return retval; - } + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); + pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); + if (pciehp_poll_mode) + int_poll_timeout(ctrl->poll_timer.data); - switch (lnk_status & 0x0F) { - case 1: - lnk_speed = PCIE_2PT5GB; - break; - default: - lnk_speed = PCIE_LNK_SPEED_UNKNOWN; - break; - } - - *value = lnk_speed; - dbg("Current link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE - return retval; + return 0; } -static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) +int pcie_init_notification(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; - int retval = 0; - u16 lnk_status; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - 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__); + if (pciehp_request_irq(ctrl)) return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); - - if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); - return retval; - } - - switch ((lnk_status & 0x03F0) >> 4){ - case 0: - lnk_wdth = PCIE_LNK_WIDTH_RESRV; - break; - case 1: - lnk_wdth = PCIE_LNK_X1; - break; - case 2: - lnk_wdth = PCIE_LNK_X2; - break; - case 4: - lnk_wdth = PCIE_LNK_X4; - break; - case 8: - lnk_wdth = PCIE_LNK_X8; - break; - case 12: - lnk_wdth = PCIE_LNK_X12; - break; - case 16: - lnk_wdth = PCIE_LNK_X16; - break; - case 32: - lnk_wdth = PCIE_LNK_X32; - break; - default: - lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; - break; - } - - *value = lnk_wdth; - dbg("Current link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE - return retval; + pcie_enable_notification(ctrl); + ctrl->notification_enabled = 1; + return 0; } -static struct hpc_ops pciehp_hpc_ops = { - .power_on_slot = hpc_power_on_slot, - .power_off_slot = hpc_power_off_slot, - .set_attention_status = hpc_set_attention_status, - .get_power_status = hpc_get_power_status, - .get_attention_status = hpc_get_attention_status, - .get_latch_status = hpc_get_latch_status, - .get_adapter_status = hpc_get_adapter_status, - - .get_max_bus_speed = hpc_get_max_lnk_speed, - .get_cur_bus_speed = hpc_get_cur_lnk_speed, - .get_max_lnk_width = hpc_get_max_lnk_width, - .get_cur_lnk_width = hpc_get_cur_lnk_width, - - .query_power_fault = hpc_query_power_fault, - .green_led_on = hpc_set_green_led_on, - .green_led_off = hpc_set_green_led_off, - .green_led_blink = hpc_set_green_led_blink, - - .release_ctlr = hpc_release_ctlr, - .check_lnk_status = hpc_check_lnk_status, -}; - -int pcie_init(struct controller * ctrl, - struct pcie_device *dev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback) +static void pcie_shutdown_notification(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr, *p; - void *instance_id = ctrl; - int rc; - static int first = 1; - u16 temp_word; - u16 cap_reg; - u16 intr_enable = 0; - u32 slot_cap; - int cap_base, saved_cap_base; - u16 slot_status, slot_ctrl; - struct pci_dev *pdev; - - DBG_ENTER_ROUTINE - - spin_lock_init(&list_lock); - php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); - - if (!php_ctlr) { /* allocate controller state data */ - err("%s: HPC controller memory allocation error!\n", __FUNCTION__); - goto abort; + if (ctrl->notification_enabled) { + pcie_disable_notification(ctrl); + pciehp_free_irq(ctrl); + ctrl->notification_enabled = 0; } +} - memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); - - pdev = dev->port; - php_ctlr->pci_dev = pdev; /* save pci_dev in context */ - - dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__, - pdev->vendor, pdev->device); +static int pcie_init_slot(struct controller *ctrl) +{ + struct slot *slot; - saved_cap_base = pcie_cap_base; + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { - dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); - goto abort_free_ctlr; - } + slot->wq = alloc_workqueue("pciehp-%u", 0, 0, PSN(ctrl)); + if (!slot->wq) + goto abort; - ctrl->cap_base = cap_base; + slot->ctrl = ctrl; + mutex_init(&slot->lock); + mutex_init(&slot->hotplug_lock); + INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); + ctrl->slot = slot; + return 0; +abort: + kfree(slot); + return -ENOMEM; +} - dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); +static void pcie_cleanup_slot(struct controller *ctrl) +{ + struct slot *slot = ctrl->slot; + cancel_delayed_work(&slot->work); + destroy_workqueue(slot->wq); + kfree(slot); +} - rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg); - if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg); +static inline void dbg_ctrl(struct controller *ctrl) +{ + int i; + u16 reg16; + struct pci_dev *pdev = ctrl->pcie->port; - if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) - && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); - goto abort_free_ctlr; - } + if (!pciehp_debug) + return; - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); - if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap); + ctrl_info(ctrl, "Hotplug Controller:\n"); + ctrl_info(ctrl, " Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", + pci_name(pdev), pdev->irq); + ctrl_info(ctrl, " Vendor ID : 0x%04x\n", pdev->vendor); + ctrl_info(ctrl, " Device ID : 0x%04x\n", pdev->device); + ctrl_info(ctrl, " Subsystem ID : 0x%04x\n", + pdev->subsystem_device); + ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", + pdev->subsystem_vendor); + ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", + pci_pcie_cap(pdev)); + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!pci_resource_len(pdev, i)) + continue; + ctrl_info(ctrl, " PCI resource [%d] : %pR\n", + i, &pdev->resource[i]); + } + ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); + ctrl_info(ctrl, " Physical Slot Number : %d\n", PSN(ctrl)); + ctrl_info(ctrl, " Attention Button : %3s\n", + ATTN_BUTTN(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " Power Controller : %3s\n", + POWER_CTRL(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " MRL Sensor : %3s\n", + MRL_SENS(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " Attention Indicator : %3s\n", + ATTN_LED(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " Power Indicator : %3s\n", + PWR_LED(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " Hot-Plug Surprise : %3s\n", + HP_SUPR_RM(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " EMI Present : %3s\n", + EMI(ctrl) ? "yes" : "no"); + ctrl_info(ctrl, " Command Completed : %3s\n", + NO_CMD_CMPL(ctrl) ? "no" : "yes"); + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); + ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); + ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); +} - if (!(slot_cap & HP_CAP)) { - dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); - goto abort_free_ctlr; - } - /* For debugging purpose */ - 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; - } - dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status); +#define FLAG(x, y) (((x) & (y)) ? '+' : '-') - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl); - if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl); +struct controller *pcie_init(struct pcie_device *dev) +{ + struct controller *ctrl; + u32 slot_cap, link_cap; + struct pci_dev *pdev = dev->port; - if (first) { - spin_lock_init(&hpc_event_lock); - first = 0; + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) { + dev_err(&dev->device, "%s: Out of memory\n", __func__); + goto abort; } - - dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc, - pci_resource_start(pdev, rc), pci_resource_len(pdev, rc)); - - 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; - - init_MUTEX(&ctrl->crit_sect); - /* setup wait queue */ + ctrl->pcie = dev; + pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); + ctrl->slot_cap = slot_cap; + mutex_init(&ctrl->ctrl_lock); init_waitqueue_head(&ctrl->queue); - - /* find the IRQ */ - php_ctlr->irq = dev->irq; - dbg("HPC interrupt = %d\n", php_ctlr->irq); - - /* Save interrupt callback info */ - php_ctlr->attention_button_callback = attention_button_callback; - php_ctlr->switch_change_callback = switch_change_callback; - php_ctlr->presence_change_callback = presence_change_callback; - php_ctlr->power_fault_callback = power_fault_callback; - php_ctlr->callback_instance_id = instance_id; - - /* return PCI Controller Info */ - php_ctlr->slot_device_offset = 0; - php_ctlr->num_slots = 1; - - /* Mask Hot-plug Interrupt Enable */ - 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; - } - - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - - 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; - } - dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word); - - 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; - } - dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base) - , slot_status); - - 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; - } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); - - if (pciehp_poll_mode) {/* Install interrupt polling code */ - /* Install and start the interrupt polling timer */ - init_timer(&php_ctlr->int_poll_timer); - start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ - } else { - /* Installs the interrupt handler */ - rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); - if (rc) { - err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); - goto abort_free_ctlr; - } - } - - 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; - } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); - dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap); - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; - - temp_word = (temp_word & ~intr_enable) | intr_enable; - - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - dbg("%s: temp_word %x\n", __FUNCTION__, temp_word); - - /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ - 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; - } - dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word); - 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; - } - dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, - SLOT_STATUS(ctrl->cap_base), slot_status); - - 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; - } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); - - /* Add this HPC instance into the HPC list */ - spin_lock(&list_lock); - if (php_ctlr_list_head == 0) { - php_ctlr_list_head = php_ctlr; - p = php_ctlr_list_head; - p->pnext = NULL; - } else { - p = php_ctlr_list_head; - - while (p->pnext) - p = p->pnext; - - p->pnext = php_ctlr; - } - spin_unlock(&list_lock); - - ctlr_seq_num++; - ctrl->hpc_ctlr_handle = php_ctlr; - ctrl->hpc_ops = &pciehp_hpc_ops; - - DBG_LEAVE_ROUTINE - return 0; - - /* We end up here for the many possible ways to fail this API. */ -abort_free_ctlr: - pcie_cap_base = saved_cap_base; - kfree(php_ctlr); + dbg_ctrl(ctrl); + /* + * Controller doesn't notify of command completion if the "No + * Command Completed Support" bit is set in Slot Capability + * register or the controller supports none of power + * controller, attention led, power led and EMI. + */ + if (NO_CMD_CMPL(ctrl) || + !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) + ctrl->no_cmd_complete = 1; + + /* Check if Data Link Layer Link Active Reporting is implemented */ + pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); + if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { + ctrl_dbg(ctrl, "Link Active Reporting supported\n"); + ctrl->link_active_reporting = 1; + } + + /* Clear all remaining event bits in Slot Status register */ + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | + PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | + PCI_EXP_SLTSTA_CC); + + /* Disable software notification */ + pcie_disable_notification(ctrl); + + ctrl_info(ctrl, "Slot #%d AttnBtn%c AttnInd%c PwrInd%c PwrCtrl%c MRL%c Interlock%c NoCompl%c LLActRep%c\n", + (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19, + FLAG(slot_cap, PCI_EXP_SLTCAP_ABP), + FLAG(slot_cap, PCI_EXP_SLTCAP_AIP), + FLAG(slot_cap, PCI_EXP_SLTCAP_PIP), + FLAG(slot_cap, PCI_EXP_SLTCAP_PCP), + FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP), + FLAG(slot_cap, PCI_EXP_SLTCAP_EIP), + FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS), + FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC)); + + if (pcie_init_slot(ctrl)) + goto abort_ctrl; + + return ctrl; + +abort_ctrl: + kfree(ctrl); abort: - DBG_LEAVE_ROUTINE - return -1; + return NULL; +} + +void pciehp_release_ctrl(struct controller *ctrl) +{ + pcie_shutdown_notification(ctrl); + pcie_cleanup_slot(ctrl); + kfree(ctrl); } diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index ff17d8e07e9..5f871f4c4af 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -27,801 +27,109 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/proc_fs.h> #include <linux/pci.h> #include "../pci.h" #include "pciehp.h" -#ifndef CONFIG_IA64 -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */ -#endif - -int pciehp_configure_device (struct controller* ctrl, struct pci_func* func) +int pciehp_configure_device(struct slot *p_slot) { - unsigned char bus; - struct pci_bus *child; - int num; - - if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - - /* Still NULL ? Well then scan for it ! */ - if (func->pci_dev == NULL) { - dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__); - - num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function)); - - if (num) - pci_bus_add_devices(ctrl->pci_dev->subordinate); - - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - if (func->pci_dev == NULL) { - dbg("ERROR: pci_dev still null\n"); - return 0; - } + struct pci_dev *dev; + struct pci_dev *bridge = p_slot->ctrl->pcie->port; + struct pci_bus *parent = bridge->subordinate; + int num, ret = 0; + struct controller *ctrl = p_slot->ctrl; + + pci_lock_rescan_remove(); + + dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); + if (dev) { + ctrl_err(ctrl, "Device %s already exists at %04x:%02x:00, cannot hot-add\n", + pci_name(dev), pci_domain_nr(parent), parent->number); + pci_dev_put(dev); + ret = -EEXIST; + goto out; } - if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); - + num = pci_scan_slot(parent, PCI_DEVFN(0, 0)); + if (num == 0) { + ctrl_err(ctrl, "No new device found\n"); + ret = -ENODEV; + goto out; } - return 0; -} - - -int pciehp_unconfigure_device(struct pci_func* func) -{ - int rc = 0; - int j; - struct pci_bus *pbus; - - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, - func->device, func->function); - pbus = func->pci_dev->bus; - - for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, - (func->device << 3) | j); - if (temp) { - pci_remove_bus_device(temp); - } - } - /* - * Some PCI Express root ports require fixup after hot-plug operation. - */ - if (pcie_mch_quirk) - pci_fixup_device(pci_fixup_final, pbus->self); - - return rc; -} - -/* - * pciehp_set_irq - * - * @bus_num: bus number of PCI device - * @dev_num: device number of PCI device - * @slot: pointer to u8 where slot number will be returned - */ -int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) -{ -#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_IO_APIC) - int rc; - u16 temp_word; - struct pci_dev fakedev; - struct pci_bus fakebus; - - fakedev.devfn = dev_num << 3; - fakedev.bus = &fakebus; - fakebus.number = bus_num; - dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); - dbg("%s: rc %d\n", __FUNCTION__, rc); - if (!rc) - return !rc; - - /* set the Edge Level Control Register (ELCR) */ - temp_word = inb(0x4d0); - temp_word |= inb(0x4d1) << 8; - - temp_word |= 0x01 << irq_num; - - /* This should only be for x86 as it sets the Edge Level Control Register */ - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); -#endif - return 0; -} + list_for_each_entry(dev, &parent->devices, bus_list) + if (pci_is_bridge(dev)) + pci_hp_add_bridge(dev); -/* More PCI configuration routines; this time centered around hotplug controller */ + pci_assign_unassigned_bridge_resources(bridge); + list_for_each_entry(dev, &parent->devices, bus_list) { + if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) + continue; -/* - * pciehp_save_config - * - * Reads configuration for all slots in a PCI bus and saves info. - * - * Note: For non-hot plug busses, the slot # saved is the device # - * - * returns 0 if success - */ -int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) -{ - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - struct pci_func *new_slot; - int sub_bus; - int max_functions; - int function; - u8 DevError; - int device = 0; - int cloop = 0; - int stop_it; - int index; - int is_hot_plug = num_ctlr_slots || first_device_num; - struct pci_bus lpci_bus, *pci_bus; - int FirstSupported, LastSupported; - - dbg("%s: Enter\n", __FUNCTION__); - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, - num_ctlr_slots, first_device_num); - - /* Decide which slots are supported */ - if (is_hot_plug) { - /********************************* - * is_hot_plug is the slot mask - *********************************/ - FirstSupported = first_device_num; - LastSupported = FirstSupported + num_ctlr_slots - 1; - } else { - FirstSupported = 0; - LastSupported = 0x1F; + pci_configure_slot(dev); } - dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, - LastSupported); - - /* Save PCI configuration space for all devices in supported slots */ - dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number); - pci_bus->number = busnumber; - dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device); - for (device = FirstSupported; device <= LastSupported; device++) { - ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - dbg("%s: ID = %x\n", __FUNCTION__, ID); - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", class_code, header_type); - - /* If multi-function device, set max_functions to 8 */ - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - dbg("%s: In do loop\n", __FUNCTION__); + pci_bus_add_devices(parent); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ - /* Recurse the subordinate bus - * get the subordinate bus number - */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - /* Save secondary bus cfg spc with this recursive call. */ - rc = pciehp_save_config(ctrl, sub_bus, 0, 0); - if (rc) - return rc; - } - } - - index = 0; - new_slot = pciehp_slot_find(busnumber, device, index++); - - dbg("%s: new_slot = %p bus %x dev %x fun %x\n", - __FUNCTION__, new_slot, busnumber, device, index-1); - - while (new_slot && (new_slot->function != (u8) function)) { - new_slot = pciehp_slot_find(busnumber, device, index++); - dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n", - __FUNCTION__, new_slot, busnumber, device, index-1); - } - if (!new_slot) { - /* Setup slot structure. */ - new_slot = pciehp_slot_create(busnumber); - dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n", - __FUNCTION__, new_slot, busnumber, device, function); - - if (new_slot == NULL) - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - /* In case of unsupported board */ - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, - (new_slot->device << 3) | new_slot->function); - dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); - /* dbg("new_slot->config_space[%x] = %x\n", - cloop, new_slot->config_space[cloop]); */ - if (rc) - return rc; - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in Class Code and Header type. - */ - - while ((function < max_functions)&&(!stop_it)) { - dbg("%s: In while loop \n", __FUNCTION__); - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - dbg("Nothing there\n"); - } else { /* Something there */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", class_code, header_type); - stop_it++; - } - } - - } while (function < max_functions); - /* End of IF (device in slot?) */ - } else if (is_hot_plug) { - /* Setup slot structure with entry for empty slot */ - new_slot = pciehp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); - } - dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot, - new_slot->bus, new_slot->device, new_slot->function); - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } /* End of FOR loop */ - - dbg("%s: Exit\n", __FUNCTION__); - return(0); + out: + pci_unlock_rescan_remove(); + return ret; } - -/* - * pciehp_save_slot_config - * - * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. - * - * returns 0 if success - */ -int pciehp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) +int pciehp_unconfigure_device(struct slot *p_slot) { - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - int sub_bus; - int max_functions; - int function; - int cloop = 0; - int stop_it; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = new_slot->bus; - - ID = 0xFFFFFFFF; - - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - /* Recurse the subordinate bus */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - /* Save the config headers for the secondary bus. */ - rc = pciehp_save_config(ctrl, sub_bus, 0, 0); - - if (rc) - return rc; - - } /* End of IF */ - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in the Class Code and the Header type. - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - } else { /* Something there */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } /* End of IF (device in slot?) */ - else { - return 2; - } - - return 0; -} - - -/* - * pciehp_save_used_resources - * - * Stores used resource information for existing boards. this is - * for boards that were in the system when this driver was loaded. - * this function is for hot plug ADD - * - * returns 0 if success - * if disable == 1(DISABLE_CARD), - * it loops for all functions of the slot and disables them. - * else, it just get resources of the function and return. - */ -int pciehp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 temp_byte; + int rc = 0; + u8 bctl = 0; + u8 presence = 0; + struct pci_dev *dev, *temp; + struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; u16 command; - u16 save_command; - u16 w_base, w_length; - u32 temp_register; - u32 save_base; - u32 base, length; - u64 base64 = 0; - int index = 0; - unsigned int devfn; - struct pci_resource *mem_node = NULL; - struct pci_resource *p_mem_node = NULL; - struct pci_resource *t_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - if (disable) - func = pciehp_slot_find(func->bus, func->device, index++); - - while ((func != NULL) && func->is_a_board) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Save the command register */ - pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); - - if (disable) { - /* disable card */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - } - - /* Check for Bridge */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - if (disable) { - /* Clear Bridge Control Register */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - } - - pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); - - bus_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!bus_node) - return -ENOMEM; + struct controller *ctrl = p_slot->ctrl; - bus_node->base = (ulong)secondary_bus; - bus_node->length = (ulong)(temp_byte - secondary_bus + 1); + ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n", + __func__, pci_domain_nr(parent), parent->number); + pciehp_get_adapter_status(p_slot, &presence); - bus_node->next = func->bus_head; - func->bus_head = bus_node; + pci_lock_rescan_remove(); - /* Save IO base and Limit registers */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte); - base = temp_byte; - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); - length = temp_byte; - - if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { - io_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; - io_node->length = (ulong)(length - base + 0x10) << 8; - - io_node->next = func->io_head; - func->io_head = io_node; - } - - /* Save memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = (ulong)w_base << 16; - mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - /* Save prefetchable memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - p_mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = (ulong)w_base << 16; - p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; + /* + * Stopping an SR-IOV PF device removes all the associated VFs, + * which will update the bus->devices list and confuse the + * iterator. Therefore, iterate in reverse so we remove the VFs + * first, then the PF. We do the same in pci_stop_bus_device(). + */ + list_for_each_entry_safe_reverse(dev, temp, &parent->devices, + bus_list) { + pci_dev_get(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + ctrl_err(ctrl, + "Cannot remove display device %s\n", + pci_name(dev)); + pci_dev_put(dev); + rc = -EINVAL; + break; } - } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - - /* Figure out IO and memory base lengths */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - - if (!disable) - pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base); - - if (!temp_register) - continue; - - base = temp_register; - - if ((base & PCI_BASE_ADDRESS_SPACE_IO) && - (!disable || (save_command & PCI_COMMAND_IO))) { - /* IO base */ - /* set temp_register = amount of IO space requested */ - base = base & 0xFFFFFFFCL; - base = (~base) + 1; - - io_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; - io_node->length = (ulong)base; - dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", - io_node->base, io_node->length); - - io_node->next = func->io_head; - func->io_head = io_node; - } else { /* map Memory */ - int prefetchable = 1; - /* struct pci_resources **res_node; */ - char *res_type_str = "PMEM"; - u32 temp_register2; - - t_mem_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!t_mem_node) - return -ENOMEM; - - if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && - (!disable || (save_command & PCI_COMMAND_MEMORY))) { - prefetchable = 0; - mem_node = t_mem_node; - res_type_str++; - } else - p_mem_node = t_mem_node; - - base = base & 0xFFFFFFF0L; - base = (~base) + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - if (prefetchable) { - p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - base64 = temp_register2; - base64 = (base64 << 32) | save_base; - - if (temp_register2) { - dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", - res_type_str, temp_register2, (u32)base64); - base64 &= 0x00000000FFFFFFFFL; - } - - if (prefetchable) { - p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - cloop += 4; - break; - default: - dbg("asur: reserved BAR type=0x%x\n", - temp_register); - break; - } - } - } /* End of base register loop */ - } else { /* Some other unknown header type */ - dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", - func->bus, func->device); } - - /* find the next device in this slot */ - if (!disable) - break; - func = pciehp_slot_find(func->bus, func->device, index++); - } - - return 0; -} - - -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -return_resource_list(struct pci_resource **func, struct pci_resource **res) -{ - struct pci_resource *node; - struct pci_resource *t_node; - - node = *func; - *func = NULL; - while (node) { - t_node = node->next; - return_resource(res, node); - node = t_node; + pci_stop_and_remove_bus_device(dev); + /* + * Ensure that no new Requests will be generated from + * the device. + */ + if (presence) { + pci_read_config_word(dev, PCI_COMMAND, &command); + command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + command |= PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(dev, PCI_COMMAND, command); + } + pci_dev_put(dev); } -} - -/* - * pciehp_return_board_resources - * - * this routine returns all resources allocated to a board to - * the available pool. - * - * returns 0 if success - */ -int pciehp_return_board_resources(struct pci_func * func, - struct resource_lists * resources) -{ - int rc; - - dbg("%s\n", __FUNCTION__); - - if (!func) - return 1; - - return_resource_list(&(func->io_head),&(resources->io_head)); - return_resource_list(&(func->mem_head),&(resources->mem_head)); - return_resource_list(&(func->p_mem_head),&(resources->p_mem_head)); - return_resource_list(&(func->bus_head),&(resources->bus_head)); - - rc = pciehp_resource_sort_and_combine(&(resources->mem_head)); - rc |= pciehp_resource_sort_and_combine(&(resources->p_mem_head)); - rc |= pciehp_resource_sort_and_combine(&(resources->io_head)); - rc |= pciehp_resource_sort_and_combine(&(resources->bus_head)); + pci_unlock_rescan_remove(); return rc; } - -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -kfree_resource_list(struct pci_resource **r) -{ - struct pci_resource *res, *tres; - - res = *r; - *r = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - -/** - * pciehp_destroy_resource_list: put node back in the resource list - * @resources: list to put nodes back - */ -void pciehp_destroy_resource_list(struct resource_lists * resources) -{ - kfree_resource_list(&(resources->io_head)); - kfree_resource_list(&(resources->mem_head)); - kfree_resource_list(&(resources->p_mem_head)); - kfree_resource_list(&(resources->bus_head)); -} - -/** - * pciehp_destroy_board_resources: put node back in the resource list - * @resources: list to put nodes back - */ -void pciehp_destroy_board_resources(struct pci_func * func) -{ - kfree_resource_list(&(func->io_head)); - kfree_resource_list(&(func->mem_head)); - kfree_resource_list(&(func->p_mem_head)); - kfree_resource_list(&(func->bus_head)); -} diff --git a/drivers/pci/hotplug/pciehprm.h b/drivers/pci/hotplug/pciehprm.h deleted file mode 100644 index 05f20fbc5f5..00000000000 --- a/drivers/pci/hotplug/pciehprm.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#ifndef _PCIEHPRM_H_ -#define _PCIEHPRM_H_ - -#ifdef CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI -#include "pciehprm_nonacpi.h" -#endif - -int pciehprm_init(enum php_ctlr_type ct); -void pciehprm_cleanup(void); -int pciehprm_print_pirt(void); -int pciehprm_find_available_resources(struct controller *ctrl); -int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); -void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); - -#ifdef DEBUG -#define RES_CHECK(this, bits) \ - { if (((this) & (bits - 1))) \ - printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } -#else -#define RES_CHECK(this, bits) -#endif - -#endif /* _PCIEHPRM_H_ */ diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c deleted file mode 100644 index 1406db35b08..00000000000 --- a/drivers/pci/hotplug/pciehprm_acpi.c +++ /dev/null @@ -1,1737 +0,0 @@ -/* - * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform - * - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <kristen.c.accardi@intel.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/acpi.h> -#include <linux/efi.h> -#include <linux/pci-acpi.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#ifdef CONFIG_IA64 -#include <asm/iosapic.h> -#endif -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/actypes.h> -#include "pciehp.h" -#include "pciehprm.h" - -#define PCI_MAX_BUS 0x100 -#define ACPI_STA_DEVICE_PRESENT 0x01 - -#define METHOD_NAME__SUN "_SUN" -#define METHOD_NAME__HPP "_HPP" -#define METHOD_NAME_OSHP "OSHP" - -/* Status code for running acpi method to gain native control */ -#define NC_NOT_RUN 0 -#define OSC_NOT_EXIST 1 -#define OSC_RUN_FAILED 2 -#define OSHP_NOT_EXIST 3 -#define OSHP_RUN_FAILED 4 -#define NC_RUN_SUCCESS 5 - -#define PHP_RES_BUS 0xA0 -#define PHP_RES_IO 0xA1 -#define PHP_RES_MEM 0xA2 -#define PHP_RES_PMEM 0xA3 - -#define BRIDGE_TYPE_P2P 0x00 -#define BRIDGE_TYPE_HOST 0x01 - -/* this should go to drivers/acpi/include/ */ -struct acpi__hpp { - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -struct acpi_php_slot { - struct acpi_php_slot *next; - struct acpi_bridge *bridge; - acpi_handle handle; - int seg; - int bus; - int dev; - int fun; - u32 sun; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - void *slot_ops; /* _STA, _EJx, etc */ - struct slot *slot; -}; /* per func */ - -struct acpi_bridge { - struct acpi_bridge *parent; - struct acpi_bridge *next; - struct acpi_bridge *child; - acpi_handle handle; - int seg; - int pbus; /* pdev->bus->number */ - int pdevice; /* PCI_SLOT(pdev->devfn) */ - int pfunction; /* PCI_DEVFN(pdev->devfn) */ - int bus; /* pdev->subordinate->number */ - struct acpi__hpp *_hpp; - struct acpi_php_slot *slots; - struct pci_resource *tmem_head; /* total from crs */ - struct pci_resource *tp_mem_head; /* total from crs */ - struct pci_resource *tio_head; /* total from crs */ - struct pci_resource *tbus_head; /* total from crs */ - struct pci_resource *mem_head; /* available */ - struct pci_resource *p_mem_head; /* available */ - struct pci_resource *io_head; /* available */ - struct pci_resource *bus_head; /* available */ - int scanned; - int type; -}; - -static struct acpi_bridge *acpi_bridges_head; - -static u8 * acpi_path_name( acpi_handle handle) -{ - acpi_status status; - static u8 path_name[ACPI_PATHNAME_MAX]; - struct acpi_buffer ret_buf = { ACPI_PATHNAME_MAX, path_name }; - - memset(path_name, 0, sizeof (path_name)); - status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf); - - if (ACPI_FAILURE(status)) - return NULL; - else - return path_name; -} - -static void acpi_get__hpp ( struct acpi_bridge *ab); -static int acpi_run_oshp ( struct acpi_bridge *ab); -static int osc_run_status = NC_NOT_RUN; -static int oshp_run_status = NC_NOT_RUN; - -static int acpi_add_slot_to_php_slots( - struct acpi_bridge *ab, - int bus_num, - acpi_handle handle, - u32 adr, - u32 sun - ) -{ - struct acpi_php_slot *aps; - static long samesun = -1; - - aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); - if (!aps) { - err ("acpi_pciehprm: alloc for aps fail\n"); - return -1; - } - memset(aps, 0, sizeof(struct acpi_php_slot)); - - aps->handle = handle; - aps->bus = bus_num; - aps->dev = (adr >> 16) & 0xffff; - aps->fun = adr & 0xffff; - aps->sun = sun; - - aps->next = ab->slots; /* cling to the bridge */ - aps->bridge = ab; - ab->slots = aps; - - ab->scanned += 1; - if (!ab->_hpp) - acpi_get__hpp(ab); - - if (osc_run_status == OSC_NOT_EXIST) - oshp_run_status = acpi_run_oshp(ab); - - if (sun != samesun) { - info("acpi_pciehprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", - aps->sun, ab->seg, aps->bus, aps->dev, aps->fun); - samesun = sun; - } - return 0; -} - -static void acpi_get__hpp ( struct acpi_bridge *ab) -{ - acpi_status status; - u8 nui[4]; - struct acpi_buffer ret_buf = { 0, NULL}; - union acpi_object *ext_obj, *package; - u8 *path_name = acpi_path_name(ab->handle); - int i, len = 0; - - /* get _hpp */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); - switch (status) { - case AE_BUFFER_OVERFLOW: - ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); - if (!ret_buf.pointer) { - err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name); - return; - } - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); - if (ACPI_SUCCESS(status)) - break; - default: - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status); - return; - } - } - - ext_obj = (union acpi_object *) ret_buf.pointer; - if (ext_obj->type != ACPI_TYPE_PACKAGE) { - err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name); - goto free_and_return; - } - - len = ext_obj->package.count; - package = (union acpi_object *) ret_buf.pointer; - for ( i = 0; (i < len) || (i < 4); i++) { - ext_obj = (union acpi_object *) &package->package.elements[i]; - switch (ext_obj->type) { - case ACPI_TYPE_INTEGER: - nui[i] = (u8)ext_obj->integer.value; - break; - default: - err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name); - goto free_and_return; - } - } - - ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); - if (!ab->_hpp) { - err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name); - goto free_and_return; - } - memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); - - ab->_hpp->cache_line_size = nui[0]; - ab->_hpp->latency_timer = nui[1]; - ab->_hpp->enable_serr = nui[2]; - ab->_hpp->enable_perr = nui[3]; - - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); - -free_and_return: - kfree(ret_buf.pointer); -} - -static int acpi_run_oshp ( struct acpi_bridge *ab) -{ - acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); - - /* run OSHP */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); - oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED; - } else { - oshp_run_status = NC_RUN_SUCCESS; - dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); - dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status); - } - return oshp_run_status; -} - -static acpi_status acpi_evaluate_crs( - acpi_handle handle, - struct acpi_resource **retbuf - ) -{ - acpi_status status; - struct acpi_buffer crsbuf; - u8 *path_name = acpi_path_name(handle); - - crsbuf.length = 0; - crsbuf.pointer = NULL; - - status = acpi_get_current_resources (handle, &crsbuf); - - switch (status) { - case AE_BUFFER_OVERFLOW: - break; /* found */ - case AE_NOT_FOUND: - dbg("acpi_pciehprm:%s _CRS not found\n", path_name); - return status; - default: - err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status); - return status; - } - - crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); - if (!crsbuf.pointer) { - err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); - return AE_NO_MEMORY; - } - - status = acpi_get_current_resources (handle, &crsbuf); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status); - kfree(crsbuf.pointer); - return status; - } - - *retbuf = crsbuf.pointer; - - return status; -} - -static void free_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res, *next; - - for (res = aprh; res; res = next) { - next = res->next; - kfree(res); - } -} - -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - -static void print_slot_resources( struct acpi_php_slot *aps) -{ - if (aps->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (aps->bus_head); - } - - if (aps->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (aps->io_head); - } - - if (aps->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (aps->mem_head); - } - - if (aps->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (aps->p_mem_head); - } -} - -static void print_pci_resources( struct acpi_bridge *ab) -{ - if (ab->tbus_head) { - dbg(" Total BUS Resources:\n"); - print_pci_resource (ab->tbus_head); - } - if (ab->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (ab->bus_head); - } - - if (ab->tio_head) { - dbg(" Total IO Resources:\n"); - print_pci_resource (ab->tio_head); - } - if (ab->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (ab->io_head); - } - - if (ab->tmem_head) { - dbg(" Total MEM Resources:\n"); - print_pci_resource (ab->tmem_head); - } - if (ab->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (ab->mem_head); - } - - if (ab->tp_mem_head) { - dbg(" Total PMEM Resources:\n"); - print_pci_resource (ab->tp_mem_head); - } - if (ab->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (ab->p_mem_head); - } - if (ab->_hpp) { - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); - } -} - -static int pciehprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - pciehp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - -static int pciehprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - pciehprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - -static int pciehprm_add_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - - for (res = *aprh; res; res = res->next) { - if ((res->base + res->length) == base) { - res->length += size; - size = 0L; - break; - } - if (res->next == *aprh) - break; - } - - if (size) { - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!res) { - err ("acpi_pciehprm: alloc for res fail\n"); - return -ENOMEM; - } - memset(res, 0, sizeof (struct pci_resource)); - - res->base = base; - res->length = size; - res->next = *aprh; - *aprh = res; - } - - return 0; -} - -static int pciehprm_add_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - int rc = 0; - - for (res = this; res && !rc; res = res->next) - rc = pciehprm_add_resource(aprh, res->base, res->length); - - return rc; -} - -static void acpi_parse_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_io *dataio; - dataio = (struct acpi_resource_io *) data; - - dbg("Io Resource\n"); - dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); - dbg(" Range minimum base: %08X\n", dataio->min_base_address); - dbg(" Range maximum base: %08X\n", dataio->max_base_address); - dbg(" Alignment: %08X\n", dataio->alignment); - dbg(" Range Length: %08X\n", dataio->range_length); -} - -static void acpi_parse_fixed_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_fixed_io *datafio; - datafio = (struct acpi_resource_fixed_io *) data; - - dbg("Fixed Io Resource\n"); - dbg(" Range base address: %08X", datafio->base_address); - dbg(" Range length: %08X", datafio->range_length); -} - -static void acpi_parse_address16_32 ( - struct acpi_bridge *ab, - union acpi_resource_data *data, - acpi_resource_type id - ) -{ - /* - * acpi_resource_address16 == acpi_resource_address32 - * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; - */ - struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; - struct pci_resource **aprh, **tprh; - - if (id == ACPI_RSTYPE_ADDRESS16) - dbg("acpi_pciehprm:16-Bit Address Space Resource\n"); - else - dbg("acpi_pciehprm:32-Bit Address Space Resource\n"); - - switch (data32->resource_type) { - case ACPI_MEMORY_RANGE: - dbg(" Resource Type: Memory Range\n"); - aprh = &ab->mem_head; - tprh = &ab->tmem_head; - - switch (data32->attribute.memory.cache_attribute) { - case ACPI_NON_CACHEABLE_MEMORY: - dbg(" Type Specific: Noncacheable memory\n"); - break; - case ACPI_CACHABLE_MEMORY: - dbg(" Type Specific: Cacheable memory\n"); - break; - case ACPI_WRITE_COMBINING_MEMORY: - dbg(" Type Specific: Write-combining memory\n"); - break; - case ACPI_PREFETCHABLE_MEMORY: - aprh = &ab->p_mem_head; - dbg(" Type Specific: Prefetchable memory\n"); - break; - default: - dbg(" Type Specific: Invalid cache attribute\n"); - break; - } - - dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); - break; - - case ACPI_IO_RANGE: - dbg(" Resource Type: I/O Range\n"); - aprh = &ab->io_head; - tprh = &ab->tio_head; - - switch (data32->attribute.io.range_attribute) { - case ACPI_NON_ISA_ONLY_RANGES: - dbg(" Type Specific: Non-ISA Io Addresses\n"); - break; - case ACPI_ISA_ONLY_RANGES: - dbg(" Type Specific: ISA Io Addresses\n"); - break; - case ACPI_ENTIRE_RANGE: - dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); - break; - default: - dbg(" Type Specific: Invalid range attribute\n"); - break; - } - break; - - case ACPI_BUS_NUMBER_RANGE: - dbg(" Resource Type: Bus Number Range(fixed)\n"); - /* fixup to be compatible with the rest of php driver */ - data32->min_address_range++; - data32->address_length--; - aprh = &ab->bus_head; - tprh = &ab->tbus_head; - break; - default: - dbg(" Resource Type: Invalid resource type. Exiting.\n"); - return; - } - - dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); - dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); - dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); - dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); - dbg(" Granularity: %08X\n", data32->granularity); - dbg(" Address range min: %08X\n", data32->min_address_range); - dbg(" Address range max: %08X\n", data32->max_address_range); - dbg(" Address translation offset: %08X\n", data32->address_translation_offset); - dbg(" Address Length: %08X\n", data32->address_length); - - if (0xFF != data32->resource_source.index) { - dbg(" Resource Source Index: %X\n", data32->resource_source.index); - /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ - } - - pciehprm_add_resource(aprh, data32->min_address_range, data32->address_length); -} - -static acpi_status acpi_parse_crs( - struct acpi_bridge *ab, - struct acpi_resource *crsbuf - ) -{ - acpi_status status = AE_OK; - struct acpi_resource *resource = crsbuf; - u8 count = 0; - u8 done = 0; - - while (!done) { - dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); - switch (resource->id) { - case ACPI_RSTYPE_IRQ: - dbg("Irq -------- Resource\n"); - break; - case ACPI_RSTYPE_DMA: - dbg("DMA -------- Resource\n"); - break; - case ACPI_RSTYPE_START_DPF: - dbg("Start DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_END_DPF: - dbg("End DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_IO: - acpi_parse_io (ab, &resource->data); - break; - case ACPI_RSTYPE_FIXED_IO: - acpi_parse_fixed_io (ab, &resource->data); - break; - case ACPI_RSTYPE_VENDOR: - dbg("Vendor -------- Resource\n"); - break; - case ACPI_RSTYPE_END_TAG: - dbg("End_tag -------- Resource\n"); - done = 1; - break; - case ACPI_RSTYPE_MEM24: - dbg("Mem24 -------- Resource\n"); - break; - case ACPI_RSTYPE_MEM32: - dbg("Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_FIXED_MEM32: - dbg("Fixed Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_ADDRESS16: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); - break; - case ACPI_RSTYPE_ADDRESS32: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); - break; - case ACPI_RSTYPE_ADDRESS64: - info("Address64 -------- Resource unparsed\n"); - break; - case ACPI_RSTYPE_EXT_IRQ: - dbg("Ext Irq -------- Resource\n"); - break; - default: - dbg("Invalid -------- resource type 0x%x\n", resource->id); - break; - } - - resource = (struct acpi_resource *) ((char *)resource + resource->length); - } - - return status; -} - -static acpi_status acpi_get_crs( struct acpi_bridge *ab) -{ - acpi_status status; - struct acpi_resource *crsbuf; - - status = acpi_evaluate_crs(ab->handle, &crsbuf); - if (ACPI_SUCCESS(status)) { - status = acpi_parse_crs(ab, crsbuf); - kfree(crsbuf); - - pciehp_resource_sort_and_combine(&ab->bus_head); - pciehp_resource_sort_and_combine(&ab->io_head); - pciehp_resource_sort_and_combine(&ab->mem_head); - pciehp_resource_sort_and_combine(&ab->p_mem_head); - - pciehprm_add_resources (&ab->tbus_head, ab->bus_head); - pciehprm_add_resources (&ab->tio_head, ab->io_head); - pciehprm_add_resources (&ab->tmem_head, ab->mem_head); - pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - } - - return status; -} - -/* find acpi_bridge downword from ab. */ -static struct acpi_bridge * -find_acpi_bridge_by_bus( - struct acpi_bridge *ab, - int seg, - int bus /* pdev->subordinate->number */ - ) -{ - struct acpi_bridge *lab = NULL; - - if (!ab) - return NULL; - - if ((ab->bus == bus) && (ab->seg == seg)) - return ab; - - if (ab->child) - lab = find_acpi_bridge_by_bus(ab->child, seg, bus); - - if (!lab) - if (ab->next) - lab = find_acpi_bridge_by_bus(ab->next, seg, bus); - - return lab; -} - -/* - * Build a device tree of ACPI PCI Bridges - */ -static void pciehprm_acpi_register_a_bridge ( - struct acpi_bridge **head, - struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ - struct acpi_bridge *cab /* child bridge to add */ - ) -{ - struct acpi_bridge *lpab; - struct acpi_bridge *lcab; - - lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); - if (!lpab) { - if (!(pab->type & BRIDGE_TYPE_HOST)) - warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); - pab->next = *head; - *head = pab; - lpab = pab; - } - - if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) - return; - - lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); - if (lcab) { - if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) - err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); - return; - } else - lcab = cab; - - lcab->parent = lpab; - lcab->next = lpab->child; - lpab->child = lcab; -} - -static acpi_status pciehprm_acpi_build_php_slots_callback( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong bus_num; - ulong seg_num; - ulong sun, adr; - ulong padr = 0; - acpi_handle phandle = NULL; - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *lab; - acpi_status status; - u8 *path_name = acpi_path_name(handle); - - /* get _SUN */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); - switch(status) { - case AE_NOT_FOUND: - return AE_OK; - default: - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status); - return status; - } - } - - /* get _ADR. _ADR must exist if _SUN exists */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); - return status; - } - - dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); - - status = acpi_get_parent(handle, &phandle); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status); - return (status); - } - - bus_num = pab->bus; - seg_num = pab->seg; - - if (pab->bus == bus_num) { - lab = pab; - } else { - dbg("WARN: pab is not parent\n"); - lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); - if (!lab) { - dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); - lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); - if (!lab) { - err("acpi_pciehprm: alloc for ab fail\n"); - return AE_NO_MEMORY; - } - memset(lab, 0, sizeof(struct acpi_bridge)); - - lab->handle = phandle; - lab->pbus = pab->bus; - lab->pdevice = (int)(padr >> 16) & 0xffff; - lab->pfunction = (int)(padr & 0xffff); - lab->bus = (int)bus_num; - lab->scanned = 0; - lab->type = BRIDGE_TYPE_P2P; - - pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); - } else - dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); - } - - acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); - - return (status); -} - -static int pciehprm_acpi_build_php_slots( - struct acpi_bridge *ab, - u32 depth - ) -{ - acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); - - /* Walk down this pci bridge to get _SUNs if any behind P2P */ - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - ab->handle, - depth, - pciehprm_acpi_build_php_slots_callback, - ab, - NULL ); - if (ACPI_FAILURE(status)) { - dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); - return -1; - } - - return 0; -} - -static void build_a_bridge( - struct acpi_bridge *pab, - struct acpi_bridge *ab - ) -{ - u8 *path_name = acpi_path_name(ab->handle); - - pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - case BRIDGE_TYPE_P2P: - dbg("acpi_pciehprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - }; - - /* build any immediate PHP slots under this pci bridge */ - pciehprm_acpi_build_php_slots(ab, 1); -} - -static struct acpi_bridge * add_p2p_bridge( - acpi_handle handle, - struct acpi_bridge *pab, /* parent */ - ulong adr - ) -{ - struct acpi_bridge *ab; - struct pci_dev *pdev; - ulong devnum, funcnum; - u8 *path_name = acpi_path_name(handle); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_pciehprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev || !pdev->subordinate) { - err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name); - kfree(ab); - return NULL; - } - - ab->handle = handle; - ab->seg = pab->seg; - ab->pbus = pab->bus; /* or pdev->bus->number */ - ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ - ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ - ab->bus = pdev->subordinate->number; - ab->scanned = 0; - ab->type = BRIDGE_TYPE_P2P; - - dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", - pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pab->bus, (u32)devnum, (u32)funcnum, path_name); - - build_a_bridge(pab, ab); - - return ab; -} - -static acpi_status scan_p2p_bridge( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *ab; - acpi_status status; - ulong adr = 0; - u8 *path_name = acpi_path_name(handle); - ulong devnum, funcnum; - struct pci_dev *pdev; - - /* get device, function */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) - err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); - return AE_OK; - } - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev) - return AE_OK; - if (!pdev->subordinate) - return AE_OK; - - ab = add_p2p_bridge(handle, pab, adr); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - (u32)1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static struct acpi_bridge * add_host_bridge( - acpi_handle handle, - ulong segnum, - ulong busnum - ) -{ - ulong adr = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get device, function: host br adr is always 0000 though. */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); - return NULL; - } - dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, - (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_pciehprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - ab->handle = handle; - ab->seg = (int)segnum; - ab->bus = ab->pbus = (int)busnum; - ab->pdevice = (int)(adr >> 16) & 0xffff; - ab->pfunction = (int)(adr & 0xffff); - ab->scanned = 0; - ab->type = BRIDGE_TYPE_HOST; - - /* get root pci bridge's current resources */ - status = acpi_get_crs(ab); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status); - kfree(ab); - return NULL; - } - - status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); - if (ACPI_FAILURE(status)) { - err("%s: status %x\n", __FUNCTION__, status); - osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED; - } else { - osc_run_status = NC_RUN_SUCCESS; - } - dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status); - - build_a_bridge(ab, ab); - - return ab; -} - -static acpi_status acpi_scan_from_root_pci_callback ( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong segnum = 0; - ulong busnum = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status); - return status; - } - segnum = 0; - } - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status); - return (status); - } - - ab = add_host_bridge(handle, segnum, busnum); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - 1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static int pciehprm_acpi_scan_pci (void) -{ - acpi_status status; - - /* - * TBD: traverse LDM device tree with the help of - * unified ACPI augmented for php device population. - */ - status = acpi_get_devices ( PCI_ROOT_HID_STRING, - acpi_scan_from_root_pci_callback, - NULL, - NULL ); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status); - return -1; - } - - return 0; -} - -int pciehprm_init(enum php_ctlr_type ctlr_type) -{ - int rc; - - if (ctlr_type != PCI) - return -ENODEV; - - dbg("pciehprm ACPI init <enter>\n"); - acpi_bridges_head = NULL; - - /* construct PCI bus:device tree of acpi_handles */ - rc = pciehprm_acpi_scan_pci(); - if (rc) - return rc; - - if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) { - err("Fails to gain control of native hot-plug\n"); - rc = -ENODEV; - } - - dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success"); - return rc; -} - -static void free_a_slot(struct acpi_php_slot *aps) -{ - dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); - - free_pci_resource (aps->io_head); - free_pci_resource (aps->bus_head); - free_pci_resource (aps->mem_head); - free_pci_resource (aps->p_mem_head); - - kfree(aps); -} - -static void free_a_bridge( struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps, *next; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - case BRIDGE_TYPE_P2P: - dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - }; - - /* free slots first */ - for (aps = ab->slots; aps; aps = next) { - next = aps->next; - free_a_slot(aps); - } - - free_pci_resource (ab->io_head); - free_pci_resource (ab->tio_head); - free_pci_resource (ab->bus_head); - free_pci_resource (ab->tbus_head); - free_pci_resource (ab->mem_head); - free_pci_resource (ab->tmem_head); - free_pci_resource (ab->p_mem_head); - free_pci_resource (ab->tp_mem_head); - - kfree(ab); -} - -static void pciehprm_free_bridges ( struct acpi_bridge *ab) -{ - if (!ab) - return; - - if (ab->child) - pciehprm_free_bridges (ab->child); - - if (ab->next) - pciehprm_free_bridges (ab->next); - - free_a_bridge(ab); -} - -void pciehprm_cleanup(void) -{ - pciehprm_free_bridges (acpi_bridges_head); -} - -static int get_number_of_slots ( - struct acpi_bridge *ab, - int selfonly - ) -{ - struct acpi_php_slot *aps; - int prev_slot = -1; - int slot_num = 0; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->dev != prev_slot) { - prev_slot = aps->dev; - slot_num++; - } - - if (ab->child) - slot_num += get_number_of_slots (ab->child, 0); - - if (selfonly) - return slot_num; - - if (ab->next) - slot_num += get_number_of_slots (ab->next, 0); - - return slot_num; -} - -static int print_acpi_resources (struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps; - int i; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); - break; - case BRIDGE_TYPE_P2P: - dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); - break; - }; - - print_pci_resources (ab); - - for ( i = -1, aps = ab->slots; aps; aps = aps->next) { - if (aps->dev == i) - continue; - dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - print_slot_resources(aps); - i = aps->dev; - } - - if (ab->child) - print_acpi_resources (ab->child); - - if (ab->next) - print_acpi_resources (ab->next); - - return 0; -} - -int pciehprm_print_pirt(void) -{ - dbg("PCIEHPRM ACPI Slots\n"); - if (acpi_bridges_head) - print_acpi_resources (acpi_bridges_head); - - return 0; -} - -static struct acpi_php_slot * get_acpi_slot ( - struct acpi_bridge *ab, - u32 sun - ) -{ - struct acpi_php_slot *aps = NULL; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->sun == sun) - return aps; - - if (!aps && ab->child) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); - if (aps) - return aps; - } - - if (!aps && ab->next) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); - if (aps) - return aps; - } - - return aps; - -} - -#if 0 -void * pciehprm_get_slot(struct slot *slot) -{ - struct acpi_bridge *ab = acpi_bridges_head; - struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); - - aps->slot = slot; - - dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - - return (void *)aps; -} -#endif - -static void pciehprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static void pciehprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -static int pciehprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = pciehprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = pciehprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= pciehprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= pciehprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= pciehprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - dbg("%s: vid = %x\n", __FUNCTION__, vid); - func = pciehp_slot_find(busn, devn, funn); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - pciehprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - pciehprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static int bind_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int status = 0; - - if (ab->bus_head) { - dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); - status = pciehprm_add_resources (&ctrl->bus_head, ab->bus_head); - if (pciehprm_delete_resources (&ab->bus_head, ctrl->bus_head)) - warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); - - if (ab->io_head) { - dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); - status = pciehprm_add_resources (&ctrl->io_head, ab->io_head); - if (pciehprm_delete_resources (&ab->io_head, ctrl->io_head)) - warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); - - if (ab->mem_head) { - dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); - status = pciehprm_add_resources (&ctrl->mem_head, ab->mem_head); - if (pciehprm_delete_resources (&ab->mem_head, ctrl->mem_head)) - warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); - - if (ab->p_mem_head) { - dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); - status = pciehprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); - if (pciehprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) - warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); - - return status; -} - -static int no_pci_resources( struct acpi_bridge *ab) -{ - return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); -} - -static int find_pci_bridge_resources ( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - struct pci_func func; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ab->pbus; - func.device = ab->pdevice; - func.function = ab->pfunction; - func.is_a_board = 1; - - /* Get used resources for this PCI bridge */ - rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD); - - ab->io_head = func.io_head; - ab->mem_head = func.mem_head; - ab->p_mem_head = func.p_mem_head; - ab->bus_head = func.bus_head; - if (ab->bus_head) - pciehprm_delete_resource(&ab->bus_head, ctrl->pci_dev->subordinate->number, 1); - - return rc; -} - -static int get_pci_resources_from_bridge( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); - - rc = find_pci_bridge_resources (ctrl, ab); - - pciehp_resource_sort_and_combine(&ab->bus_head); - pciehp_resource_sort_and_combine(&ab->io_head); - pciehp_resource_sort_and_combine(&ab->mem_head); - pciehp_resource_sort_and_combine(&ab->p_mem_head); - - pciehprm_add_resources (&ab->tbus_head, ab->bus_head); - pciehprm_add_resources (&ab->tio_head, ab->io_head); - pciehprm_add_resources (&ab->tmem_head, ab->mem_head); - pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - - return rc; -} - -static int get_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - if (no_pci_resources(ab)) { - dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); - rc = get_pci_resources_from_bridge(ctrl, ab); - } - - return rc; -} - -/* - * Get resources for this ctrl. - * 1. get total resources from ACPI _CRS or bridge (this ctrl) - * 2. find used resources of existing adapters - * 3. subtract used resources from total resources - */ -int pciehprm_find_available_resources( struct controller *ctrl) -{ - int rc = 0; - struct acpi_bridge *ab; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); - if (!ab) { - err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); - return -1; - } - if (no_pci_resources(ab)) { - rc = get_pci_resources(ctrl, ab); - if (rc) { - err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); - return -1; - } - } - - rc = bind_pci_resources(ctrl, ab); - dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - pciehprm_dump_ctrl_res(ctrl); - - bind_pci_resources_to_slots (ctrl); - - dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - pciehprm_dump_ctrl_res(ctrl); - - return rc; -} - -int pciehprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type - ) -{ - struct acpi_bridge *ab; - struct pci_bus lpci_bus, *pci_bus; - int rc = 0; - unsigned int devfn; - u8 cls= 0x08; /* default cache line size */ - u8 lt = 0x40; /* default latency timer */ - u8 ep = 0; - u8 es = 0; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); - - if (ab) { - if (ab->_hpp) { - lt = (u8)ab->_hpp->latency_timer; - cls = (u8)ab->_hpp->cache_line_size; - ep = (u8)ab->_hpp->enable_perr; - es = (u8)ab->_hpp->enable_serr; - } else - dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - } else - dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); - } - - /* set base Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); - dbg(" set latency timer =0x%02x: %x\n", lt, rc); - - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); - dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); - - return rc; -} - -void pciehprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u16 command, cmd, bcommand, bcmd; - struct pci_bus lpci_bus, *pci_bus; - struct acpi_bridge *ab; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &cmd); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcmd); - } - - command = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - bcommand = bcmd | PCI_BRIDGE_CTL_NO_ISA; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); - if (ab) { - if (ab->_hpp) { - if (ab->_hpp->enable_perr) { - command |= PCI_COMMAND_PARITY; - bcommand |= PCI_BRIDGE_CTL_PARITY; - } else { - command &= ~PCI_COMMAND_PARITY; - bcommand &= ~PCI_BRIDGE_CTL_PARITY; - } - if (ab->_hpp->enable_serr) { - command |= PCI_COMMAND_SERR; - bcommand |= PCI_BRIDGE_CTL_SERR; - } else { - command &= ~PCI_COMMAND_SERR; - bcommand &= ~PCI_BRIDGE_CTL_SERR; - } - } else - dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - } else - dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - - if (command != cmd) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - } - if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } -} diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c deleted file mode 100644 index 76c727c74cc..00000000000 --- a/drivers/pci/hotplug/pciehprm_nonacpi.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <asm/uaccess.h> -#ifdef CONFIG_IA64 -#include <asm/iosapic.h> -#endif - -#include "pciehp.h" -#include "pciehprm.h" -#include "pciehprm_nonacpi.h" - - -void pciehprm_cleanup(void) -{ - return; -} - -int pciehprm_print_pirt(void) -{ - return 0; -} - -int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) -{ - - *sun = (u8) (ctrl->first_slot); - return 0; -} - - -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - - -static void phprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static int phprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int phprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - pciehp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - - -static int phprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - phprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = phprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int pciehprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - pciehp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__, - vid, busn, devn, funn); - func = pciehp_slot_find(busn, devn, funn); - dbg("%s: func = %p\n", __FUNCTION__,func); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - phprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - phprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static void phprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -/* - * phprm_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int pciehprm_find_available_resources(struct controller *ctrl) -{ - struct pci_func func; - u32 rc; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ctrl->bus; - func.device = ctrl->device; - func.function = ctrl->function; - func.is_a_board = 1; - - /* Get resources for this PCI bridge */ - rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD); - dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc); - - if (func.mem_head) - func.mem_head->next = ctrl->mem_head; - ctrl->mem_head = func.mem_head; - - if (func.p_mem_head) - func.p_mem_head->next = ctrl->p_mem_head; - ctrl->p_mem_head = func.p_mem_head; - - if (func.io_head) - func.io_head->next = ctrl->io_head; - ctrl->io_head = func.io_head; - - if(func.bus_head) - func.bus_head->next = ctrl->bus_head; - ctrl->bus_head = func.bus_head; - - if (ctrl->bus_head) - pciehprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); - - dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - - dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__); - - bind_pci_resources_to_slots (ctrl); - - dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - - return (rc); -} - -int pciehprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u32 rc; - u8 temp_byte; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - temp_byte = 0x40; /* hard coded value for LT */ - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, - func->bus, func->device, func->function); - return rc; - } - } - - /* set base Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - return rc; - } - - /* set Cache Line size */ - temp_byte = 0x08; /* hard coded value for CLS */ - - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - - if (rc) { - dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - } - - /* set enable_perr */ - /* set enable_serr */ - - return rc; -} - -void pciehprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u16 command, bcommand; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - - command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR - | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - - bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR - | PCI_BRIDGE_CTL_NO_ISA; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } -} - -static int legacy_pciehprm_init_pci(void) -{ - return 0; -} - -int pciehprm_init(enum php_ctlr_type ctrl_type) -{ - int retval; - - switch (ctrl_type) { - case PCI: - retval = legacy_pciehprm_init_pci(); - break; - default: - retval = -ENODEV; - break; - } - - return retval; -} diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.h b/drivers/pci/hotplug/pciehprm_nonacpi.h deleted file mode 100644 index b10603b0e95..00000000000 --- a/drivers/pci/hotplug/pciehprm_nonacpi.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#ifndef _PCIEHPRM_NONACPI_H_ -#define _PCIEHPRM_NONACPI_H_ - -struct irq_info { - u8 bus, devfn; /* bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__ ((packed)) irq[4]; - u8 slot; /* slot number, 0=onboard */ - u8 rfu; -} __attribute__ ((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__ ((packed)); - -#endif /* _PCIEHPRM_NONACPI_H_ */ diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 3194d51c6ec..d062c008fc9 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -1,5 +1,5 @@ /* - * PCI Hot Plug Controller Skeleton Driver - 0.2 + * PCI Hot Plug Controller Skeleton Driver - 0.3 * * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2003 IBM Corp. @@ -21,26 +21,27 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * This driver is to be used as a skeleton driver to be show how to interface + * This driver is to be used as a skeleton driver to show how to interface * with the pci hotplug core easily. * * Send feedback to <greg@kroah.com> * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/init.h> -#include "pci_hotplug.h" +#define SLOT_NAME_SIZE 10 struct slot { u8 number; struct hotplug_slot *hotplug_slot; struct list_head slot_list; + char name[SLOT_NAME_SIZE]; }; static LIST_HEAD(slot_list); @@ -50,17 +51,15 @@ static LIST_HEAD(slot_list); #define dbg(format, arg...) \ do { \ if (debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ + printk(KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - - /* local variables */ -static int debug; +static bool debug; static int num_slots; #define DRIVER_VERSION "0.3" @@ -83,7 +82,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops skel_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, @@ -99,7 +97,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in code here to enable the specified slot @@ -108,13 +106,12 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) return retval; } - static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in code here to disable the specified slot @@ -128,21 +125,21 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); switch (status) { - case 0: - /* - * Fill in code here to turn light off - */ - break; - - case 1: - default: - /* - * Fill in code here to turn light on - */ - break; + case 0: + /* + * Fill in code here to turn light off + */ + break; + + case 1: + default: + /* + * Fill in code here to turn light on + */ + break; } return retval; @@ -153,15 +150,15 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); switch (value) { - case 0: - /* Specify a test here */ - break; - case 1: - /* Specify another test here */ - break; + case 0: + /* Specify a test here */ + break; + case 1: + /* Specify another test here */ + break; } return retval; @@ -172,7 +169,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in logic to get the current power status of the specific @@ -187,7 +184,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in logic to get the current attention status of the specific @@ -202,7 +199,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in logic to get the current latch status of the specific @@ -217,7 +214,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); /* * Fill in logic to get the current adapter status of the specific @@ -231,14 +228,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } -#define SLOT_NAME_SIZE 10 static void make_slot_name(struct slot *slot) { /* @@ -257,8 +252,7 @@ static int __init init_slots(void) struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - char *name; - int retval = -ENOMEM; + int retval; int i; /* @@ -266,50 +260,48 @@ static int __init init_slots(void) * with the pci_hotplug subsystem. */ for (i = 0; i < num_slots; ++i) { - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + retval = -ENOMEM; goto error; - memset(slot, 0, sizeof(struct slot)); + } - hotplug_slot = kmalloc(sizeof(struct hotplug_slot), - GFP_KERNEL); - if (!hotplug_slot) + hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) { + retval = -ENOMEM; goto error_slot; - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + } slot->hotplug_slot = hotplug_slot; - info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!info) + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + retval = -ENOMEM; goto error_hpslot; - memset(info, 0, sizeof (struct hotplug_slot_info)); + } hotplug_slot->info = info; - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) - goto error_info; - hotplug_slot->name = name; - slot->number = i; + hotplug_slot->name = slot->name; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; make_slot_name(slot); hotplug_slot->ops = &skel_hotplug_slot_ops; - + /* * Initialize the slot info structure with some known * good values. */ - info->power_status = get_power_status(slot); - info->attention_status = get_attention_status(slot); - info->latch_status = get_latch_status(slot); - info->adapter_status = get_adapter_status(slot); - + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); + dbg("registering slot %d\n", i); retval = pci_hp_register(slot->hotplug_slot); if (retval) { err("pci_hp_register failed with error %d\n", retval); - goto error_name; + goto error_info; } /* add slot to our internal list */ @@ -317,8 +309,6 @@ static int __init init_slots(void) } return 0; -error_name: - kfree(name); error_info: kfree(info); error_hpslot: @@ -346,7 +336,7 @@ static void __exit cleanup_slots(void) pci_hp_deregister(slot->hotplug_slot); } } - + static int __init pcihp_skel_init(void) { int retval; @@ -354,7 +344,7 @@ static int __init pcihp_skel_init(void) info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); /* * Do specific initialization stuff for your driver here - * Like initializing your controller hardware (if any) and + * like initializing your controller hardware (if any) and * determining the number of slots you have in the system * right now. */ diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c new file mode 100644 index 00000000000..e246a10a0d2 --- /dev/null +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * Copyright (C) 2003-2004 Intel Corporation + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/pci.h> +#include <linux/export.h> +#include <linux/pci_hotplug.h> + +static struct hpp_type0 pci_default_type0 = { + .revision = 1, + .cache_line_size = 8, + .latency_timer = 0x40, + .enable_serr = 0, + .enable_perr = 0, +}; + +static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) +{ + u16 pci_cmd, pci_bctl; + + if (!hpp) { + /* + * Perhaps we *should* use default settings for PCIe, but + * pciehp didn't, so we won't either. + */ + if (pci_is_pcie(dev)) + return; + dev_info(&dev->dev, "using default PCI settings\n"); + hpp = &pci_default_type0; + } + + if (hpp->revision > 1) { + dev_warn(&dev->dev, + "PCI settings rev %d not supported; using defaults\n", + hpp->revision); + hpp = &pci_default_type0; + } + + 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_type1(struct pci_dev *dev, struct hpp_type1 *hpp) +{ + if (hpp) + dev_warn(&dev->dev, "PCI-X settings not supported\n"); +} + +static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) +{ + int pos; + u32 reg32; + + if (!hpp) + return; + + if (hpp->revision > 1) { + dev_warn(&dev->dev, "PCIe settings rev %d not supported\n", + hpp->revision); + return; + } + + /* Initialize Device Control Register */ + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, + ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or); + + /* Initialize Link Control Register */ + if (dev->subordinate) + pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, + ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or); + + /* Find Advanced Error Reporting Enhanced Capability */ + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + 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 + */ +} + +void pci_configure_slot(struct pci_dev *dev) +{ + struct pci_dev *cdev; + struct hotplug_params hpp; + int ret; + + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + + pcie_bus_configure_settings(dev->bus); + + memset(&hpp, 0, sizeof(hpp)); + ret = pci_get_hp_params(dev, &hpp); + if (ret) + dev_warn(&dev->dev, "no hotplug settings from platform\n"); + + program_hpp_type2(dev, hpp.t2); + program_hpp_type1(dev, hpp.t1); + program_hpp_type0(dev, hpp.t0); + + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + pci_configure_slot(cdev); + } +} +EXPORT_SYMBOL_GPL(pci_configure_slot); diff --git a/drivers/pci/hotplug/rpadlpar.h b/drivers/pci/hotplug/rpadlpar.h index 4a0a59b82ea..81df93931ad 100644 --- a/drivers/pci/hotplug/rpadlpar.h +++ b/drivers/pci/hotplug/rpadlpar.h @@ -15,10 +15,10 @@ #ifndef _RPADLPAR_IO_H_ #define _RPADLPAR_IO_H_ -extern int dlpar_sysfs_init(void); -extern void dlpar_sysfs_exit(void); +int dlpar_sysfs_init(void); +void dlpar_sysfs_exit(void); -extern int dlpar_add_slot(char *drc_name); -extern int dlpar_remove_slot(char *drc_name); +int dlpar_add_slot(char *drc_name); +int dlpar_remove_slot(char *drc_name); #endif diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index fcb66b9a0e2..7660232ef46 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -14,12 +14,17 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#undef DEBUG + #include <linux/init.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/string.h> +#include <linux/vmalloc.h> #include <asm/pci-bridge.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/rtas.h> #include <asm/vio.h> @@ -27,7 +32,7 @@ #include "rpaphp.h" #include "rpadlpar.h" -static DECLARE_MUTEX(rpadlpar_sem); +static DEFINE_MUTEX(rpadlpar_mutex); #define DLPAR_MODULE_NAME "rpadlpar_io" @@ -63,7 +68,7 @@ static struct device_node *find_php_slot_pci_node(char *drc_name, char *type; int rc; - while ((np = of_find_node_by_type(np, "pci"))) { + while ((np = of_find_node_by_name(np, "pci"))) { rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL); if (rc == 0) if (!strcmp(drc_name, name) && !strcmp(drc_type, type)) @@ -98,77 +103,27 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) return NULL; } -static struct slot *find_slot(struct device_node *dn) +/** + * find_php_slot - return hotplug slot structure for device node + * @dn: target &device_node + * + * This routine will return the hotplug slot structure + * for a given device node. Note that built-in PCI slots + * may be dlpar-able, but not hot-pluggable, so this routine + * will return NULL for built-in PCI slots. + */ +static struct slot *find_php_slot(struct device_node *dn) { struct list_head *tmp, *n; struct slot *slot; - list_for_each_safe(tmp, n, &rpaphp_slot_head) { - slot = list_entry(tmp, struct slot, rpaphp_slot_list); - if (slot->dn == dn) - return slot; - } - - return NULL; -} - -static void rpadlpar_claim_one_bus(struct pci_bus *b) -{ - struct list_head *ld; - struct pci_bus *child_bus; - - for (ld = b->devices.next; ld != &b->devices; ld = ld->next) { - struct pci_dev *dev = pci_dev_b(ld); - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - - if (r->parent || !r->start || !r->flags) - continue; - rpaphp_claim_resource(dev, i); - } + list_for_each_safe(tmp, n, &rpaphp_slot_head) { + slot = list_entry(tmp, struct slot, rpaphp_slot_list); + if (slot->dn == dn) + return slot; } - list_for_each_entry(child_bus, &b->children, node) - rpadlpar_claim_one_bus(child_bus); -} - -static int pci_add_secondary_bus(struct device_node *dn, - struct pci_dev *bridge_dev) -{ - struct pci_dn *pdn = dn->data; - struct pci_controller *hose = pdn->phb; - struct pci_bus *child; - u8 sec_busno; - - /* Get busno of downstream bus */ - pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno); - - /* Allocate and add to children of bridge_dev->bus */ - child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno); - if (!child) { - printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__); - return -ENOMEM; - } - - sprintf(child->name, "PCI Bus #%02x", child->number); - - /* Fixup subordinate bridge bases and resources */ - pcibios_fixup_bus(child); - - /* Claim new bus resources */ - rpadlpar_claim_one_bus(bridge_dev->bus); - - if (hose->last_busno < child->number) - hose->last_busno = child->number; - - pdn->bussubno = child->number; - - /* ioremap() for child bus, which may or may not succeed */ - remap_bus_range(child); - - return 0; + return NULL; } static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, @@ -185,115 +140,93 @@ static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, return NULL; } -static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) +static void dlpar_pci_add_bus(struct device_node *dn) { - struct pci_dn *pdn = dn->data; - struct pci_controller *hose = pdn->phb; + struct pci_dn *pdn = PCI_DN(dn); + struct pci_controller *phb = pdn->phb; struct pci_dev *dev = NULL; - /* Scan phb bus for EADS device, adding new one to bus->devices */ - if (!pci_scan_single_device(hose->bus, pdn->devfn)) { - printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__); - return NULL; - } + eeh_add_device_tree_early(dn); - /* Add new devices to global lists. Register in proc, sysfs. */ - pci_bus_add_devices(hose->bus); + /* Add EADS device to PHB bus, adding new entry to bus->devices */ + dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); + if (!dev) { + printk(KERN_ERR "%s: failed to create pci dev for %s\n", + __func__, dn->full_name); + return; + } - /* Confirm new bridge dev was created */ - dev = dlpar_find_new_dev(hose->bus, dn); - if (dev) { - if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { - printk(KERN_ERR "%s: unexpected header type %d\n", - __FUNCTION__, dev->hdr_type); - return NULL; - } + /* Scan below the new bridge */ + if (pci_is_bridge(dev)) + of_scan_pci_bridge(dev); - if (pci_add_secondary_bus(dn, dev)) - return NULL; - } + /* Map IO space for child bus, which may or may not succeed */ + pcibios_map_io_space(dev->subordinate); - return dev; + /* Finish adding it : resource allocation, adding devices, etc... + * Note that we need to perform the finish pass on the -parent- + * bus of the EADS bridge so the bridge device itself gets + * properly added + */ + pcibios_finish_adding_to_bus(phb->bus); } static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) { struct pci_dev *dev; - int rc; + struct pci_controller *phb; - if (rpaphp_find_pci_bus(dn)) + if (pcibios_find_pci_bus(dn)) return -EINVAL; /* Add pci bus */ - dev = dlpar_pci_add_bus(dn); + dlpar_pci_add_bus(dn); + + /* Confirm new bridge dev was created */ + phb = PCI_DN(dn)->phb; + dev = dlpar_find_new_dev(phb->bus, dn); + if (!dev) { - printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__, + printk(KERN_ERR "%s: unable to add bus %s\n", __func__, drc_name); return -EIO; } - if (dn->child) { - rc = rpaphp_config_pci_adapter(dev->subordinate); - if (rc < 0) { - printk(KERN_ERR "%s: unable to enable slot %s\n", - __FUNCTION__, drc_name); - return -EIO; - } + if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { + printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n", + __func__, dev->hdr_type, drc_name); + return -EIO; } /* Add hotplug slot */ if (rpaphp_add_slot(dn)) { printk(KERN_ERR "%s: unable to add hotplug slot %s\n", - __FUNCTION__, drc_name); + __func__, drc_name); return -EIO; } return 0; } -static int dlpar_remove_root_bus(struct pci_controller *phb) -{ - struct pci_bus *phb_bus; - int rc; - - phb_bus = phb->bus; - if (!(list_empty(&phb_bus->children) && - list_empty(&phb_bus->devices))) { - return -EBUSY; - } - - rc = pcibios_remove_root_bus(phb); - if (rc) - return -EIO; - - device_unregister(phb_bus->bridge); - pci_remove_bus(phb_bus); - - return 0; -} - static int dlpar_remove_phb(char *drc_name, struct device_node *dn) { struct slot *slot; struct pci_dn *pdn; int rc = 0; - if (!rpaphp_find_pci_bus(dn)) + if (!pcibios_find_pci_bus(dn)) return -EINVAL; - slot = find_slot(dn); - if (slot) { - /* Remove hotplug slot */ - if (rpaphp_remove_slot(slot)) { - printk(KERN_ERR - "%s: unable to remove hotplug slot %s\n", - __FUNCTION__, drc_name); - return -EIO; - } + /* If pci slot is hotpluggable, use hotplug to remove it */ + slot = find_php_slot(dn); + if (slot && rpaphp_deregister_slot(slot)) { + printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", + __func__, drc_name); + return -EIO; } pdn = dn->data; BUG_ON(!pdn || !pdn->phb); - rc = dlpar_remove_root_bus(pdn->phb); + rc = remove_phb_dynamic(pdn->phb); if (rc < 0) return rc; @@ -306,7 +239,7 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) { struct pci_controller *phb; - if (PCI_DN(dn)->phb) { + if (PCI_DN(dn) && PCI_DN(dn)->phb) { /* PHB already exists */ return -EINVAL; } @@ -317,7 +250,7 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) if (rpaphp_add_slot(dn)) { printk(KERN_ERR "%s: unable to add hotplug slot %s\n", - __FUNCTION__, drc_name); + __func__, drc_name); return -EIO; } return 0; @@ -331,7 +264,7 @@ static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn) if (!vio_register_device_node(dn)) { printk(KERN_ERR "%s: failed to register vio node %s\n", - __FUNCTION__, drc_name); + __func__, drc_name); return -EIO; } return 0; @@ -341,9 +274,8 @@ static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn) * dlpar_add_slot - DLPAR add an I/O Slot * @drc_name: drc-name of newly added slot * - * Make the hotplug module and the kernel aware - * of a newly added I/O Slot. - * Return Codes - + * Make the hotplug module and the kernel aware of a newly added I/O Slot. + * Return Codes: * 0 Success * -ENODEV Not a valid drc_name * -EINVAL Slot already added @@ -356,7 +288,7 @@ int dlpar_add_slot(char *drc_name) int node_type; int rc = -EIO; - if (down_interruptible(&rpadlpar_sem)) + if (mutex_lock_interruptible(&rpadlpar_mutex)) return -ERESTARTSYS; /* Find newly added node */ @@ -380,16 +312,16 @@ int dlpar_add_slot(char *drc_name) printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name); exit: - up(&rpadlpar_sem); + mutex_unlock(&rpadlpar_mutex); return rc; } /** * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot * @drc_name: drc-name of newly added slot + * @dn: &device_node * - * Remove the kernel and hotplug representations - * of an I/O Slot. + * Remove the kernel and hotplug representations of an I/O Slot. * Return Codes: * 0 Success * -EINVAL Vio dev doesn't exist @@ -407,11 +339,11 @@ static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn) } /** - * dlpar_remove_slot - DLPAR remove a PCI I/O Slot + * dlpar_remove_pci_slot - DLPAR remove a PCI I/O Slot * @drc_name: drc-name of newly added slot + * @dn: &device_node * - * Remove the kernel and hotplug representations - * of a PCI I/O Slot. + * Remove the kernel and hotplug representations of a PCI I/O Slot. * Return Codes: * 0 Success * -ENODEV Not a valid drc_name @@ -421,39 +353,59 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) { struct pci_bus *bus; struct slot *slot; + int ret = 0; - bus = rpaphp_find_pci_bus(dn); - if (!bus) - return -EINVAL; + pci_lock_rescan_remove(); - slot = find_slot(dn); + bus = pcibios_find_pci_bus(dn); + if (!bus) { + ret = -EINVAL; + goto out; + } + + pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", + bus->self ? pci_name(bus->self) : "<!PHB!>"); + + slot = find_php_slot(dn); if (slot) { - /* Remove hotplug slot */ - if (rpaphp_remove_slot(slot)) { + pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n", + pci_domain_nr(bus), bus->number); + + if (rpaphp_deregister_slot(slot)) { printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", - __FUNCTION__, drc_name); - return -EIO; + __func__, drc_name); + ret = -EIO; + goto out; } } - if (unmap_bus_range(bus)) { + /* Remove all devices below slot */ + pcibios_remove_pci_devices(bus); + + /* Unmap PCI IO space */ + if (pcibios_unmap_io_space(bus)) { printk(KERN_ERR "%s: failed to unmap bus range\n", - __FUNCTION__); - return -ERANGE; + __func__); + ret = -ERANGE; + goto out; } + /* Remove the EADS bridge device itself */ BUG_ON(!bus->self); - pci_remove_bus_device(bus->self); - return 0; + pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); + pci_stop_and_remove_bus_device(bus->self); + + out: + pci_unlock_rescan_remove(); + return ret; } /** * dlpar_remove_slot - DLPAR remove an I/O Slot * @drc_name: drc-name of newly added slot * - * Remove the kernel and hotplug representations - * of an I/O Slot. + * Remove the kernel and hotplug representations of an I/O Slot. * Return Codes: * 0 Success * -ENODEV Not a valid drc_name @@ -467,7 +419,7 @@ int dlpar_remove_slot(char *drc_name) int node_type; int rc = 0; - if (down_interruptible(&rpadlpar_sem)) + if (mutex_lock_interruptible(&rpadlpar_mutex)) return -ERESTARTSYS; dn = find_dlpar_node(drc_name, &node_type); @@ -487,9 +439,11 @@ int dlpar_remove_slot(char *drc_name) rc = dlpar_remove_pci_slot(drc_name, dn); break; } + vm_unmap_aliases(); + printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name); exit: - up(&rpadlpar_sem); + mutex_unlock(&rpadlpar_mutex); return rc; } @@ -506,7 +460,7 @@ int __init rpadlpar_io_init(void) if (!is_dlpar_capable()) { printk(KERN_WARNING "%s: partition not DLPAR capable\n", - __FUNCTION__); + __func__); return -EPERM; } diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index db69be85b45..a796301ea03 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -14,53 +14,27 @@ */ #include <linux/kobject.h> #include <linux/string.h> -#include "pci_hotplug.h" +#include <linux/pci.h> +#include <linux/pci_hotplug.h> #include "rpadlpar.h" +#include "../pci.h" #define DLPAR_KOBJ_NAME "control" -#define ADD_SLOT_ATTR_NAME "add_slot" -#define REMOVE_SLOT_ATTR_NAME "remove_slot" -#define MAX_DRC_NAME_LEN 64 - -/* Store return code of dlpar operation in attribute struct */ -struct dlpar_io_attr { - int rc; - struct attribute attr; - ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf, - size_t nbytes); -}; - -/* Common show callback for all attrs, display the return code - * of the dlpar op */ -static ssize_t -dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return sprintf(buf, "%d\n", dlpar_attr->rc); -} - -static ssize_t -dlpar_attr_store(struct kobject * kobj, struct attribute * attr, - const char *buf, size_t nbytes) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return dlpar_attr->store ? - dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO; -} +/* Those two have no quotes because they are passed to __ATTR() which + * stringifies the argument (yuck !) + */ +#define ADD_SLOT_ATTR_NAME add_slot +#define REMOVE_SLOT_ATTR_NAME remove_slot -static struct sysfs_ops dlpar_attr_sysfs_ops = { - .show = dlpar_attr_show, - .store = dlpar_attr_store, -}; +#define MAX_DRC_NAME_LEN 64 -static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; char *end; + int rc; if (nbytes >= MAX_DRC_NAME_LEN) return 0; @@ -72,15 +46,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_add_slot(drc_name); + rc = dlpar_add_slot(drc_name); + if (rc) + return rc; return nbytes; } -static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} + +static ssize_t remove_slot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; + int rc; char *end; if (nbytes >= MAX_DRC_NAME_LEN) @@ -93,22 +77,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_remove_slot(drc_name); + rc = dlpar_remove_slot(drc_name); + if (rc) + return rc; return nbytes; } -static struct dlpar_io_attr add_slot_attr = { - .rc = 0, - .attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, }, - .store = add_slot_store, -}; +static ssize_t remove_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} -static struct dlpar_io_attr remove_slot_attr = { - .rc = 0, - .attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644}, - .store = remove_slot_store, -}; +static struct kobj_attribute add_slot_attr = + __ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store); + +static struct kobj_attribute remove_slot_attr = + __ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store); static struct attribute *default_attrs[] = { &add_slot_attr.attr, @@ -116,36 +102,29 @@ static struct attribute *default_attrs[] = { NULL, }; -static void dlpar_io_release(struct kobject *kobj) -{ - /* noop */ - return; -} - -struct kobj_type ktype_dlpar_io = { - .release = dlpar_io_release, - .sysfs_ops = &dlpar_attr_sysfs_ops, - .default_attrs = default_attrs, +static struct attribute_group dlpar_attr_group = { + .attrs = default_attrs, }; -struct kset dlpar_io_kset = { - .subsys = &pci_hotplug_slots_subsys, - .kobj = {.name = DLPAR_KOBJ_NAME, .ktype=&ktype_dlpar_io,}, - .ktype = &ktype_dlpar_io, -}; +static struct kobject *dlpar_kobj; int dlpar_sysfs_init(void) { - if (kset_register(&dlpar_io_kset)) { - printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + int error; + + dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, + &pci_slots_kset->kobj); + if (!dlpar_kobj) return -EINVAL; - } - return 0; + error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group); + if (error) + kobject_put(dlpar_kobj); + return error; } void dlpar_sysfs_exit(void) { - kset_unregister(&dlpar_io_kset); + sysfs_remove_group(dlpar_kobj, &dlpar_attr_group); + kobject_put(dlpar_kobj); } diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 71ea5f9bb28..b2593e876a0 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -28,7 +28,7 @@ #define _PPC64PHP_H #include <linux/pci.h> -#include "pci_hotplug.h" +#include <linux/pci_hotplug.h> #define DR_INDICATOR 9002 #define DR_ENTITY_SENSE 9003 @@ -46,12 +46,12 @@ #define PRESENT 1 /* Card in slot */ #define MY_NAME "rpaphp" -extern int debug; +extern bool rpaphp_debug; #define dbg(format, arg...) \ do { \ - if (debug) \ + if (rpaphp_debug) \ printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## arg); \ + MY_NAME , ## 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) @@ -74,7 +74,6 @@ struct slot { u32 type; u32 power_domain; char *name; - char *location; struct device_node *dn; struct pci_bus *bus; struct list_head *pci_devs; @@ -83,32 +82,22 @@ struct slot { extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; extern struct list_head rpaphp_slot_head; -extern int num_slots; /* function prototypes */ /* rpaphp_pci.c */ -extern struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn); -extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); -extern int rpaphp_enable_pci_slot(struct slot *slot); -extern int register_pci_slot(struct slot *slot); -extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); - -extern int rpaphp_config_pci_adapter(struct pci_bus *bus); -extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); +int rpaphp_enable_slot(struct slot *slot); +int rpaphp_get_sensor_state(struct slot *slot, int *state); /* rpaphp_core.c */ -extern int rpaphp_add_slot(struct device_node *dn); -extern int rpaphp_remove_slot(struct slot *slot); -extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, +int rpaphp_add_slot(struct device_node *dn); +int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, char **drc_name, char **drc_type, int *drc_power_domain); /* rpaphp_slot.c */ -extern void dealloc_slot_struct(struct slot *slot); -extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); -extern int register_slot(struct slot *slot); -extern int deregister_slot(struct slot *slot); -extern int rpaphp_get_power_status(struct slot *slot, u8 * value); -extern int rpaphp_set_attention_status(struct slot *slot, u8 status); - +void dealloc_slot_struct(struct slot *slot); +struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); +int rpaphp_register_slot(struct slot *slot); +int rpaphp_deregister_slot(struct slot *slot); + #endif /* _PPC64PHP_H */ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index cf075c34b57..93aa29f6d39 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -22,27 +22,24 @@ * Send feedback to <lxie@us.ibm.com> * */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/pci.h> -#include <linux/slab.h> +#include <linux/pci_hotplug.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/vmalloc.h> #include <asm/eeh.h> /* for eeh_add_device() */ #include <asm/rtas.h> /* rtas_call */ #include <asm/pci-bridge.h> /* for pci_controller */ #include "../pci.h" /* for pci_add_new_bus */ /* and pci_do_scan_bus */ #include "rpaphp.h" -#include "pci_hotplug.h" -int debug; -static struct semaphore rpaphp_sem; +bool rpaphp_debug; LIST_HEAD(rpaphp_slot_head); -int num_slots; +EXPORT_SYMBOL_GPL(rpaphp_slot_head); #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" @@ -54,114 +51,89 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, 0644); - -static int enable_slot(struct hotplug_slot *slot); -static int disable_slot(struct hotplug_slot *slot); -static int set_attention_status(struct hotplug_slot *slot, u8 value); -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_adapter_status(struct hotplug_slot *slot, u8 * value); -static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); - -struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, -}; - -static int rpaphp_get_attention_status(struct slot *slot) -{ - return slot->hotplug_slot->info->attention_status; -} +module_param_named(debug, rpaphp_debug, bool, 0644); /** * set_attention_status - set attention LED + * @hotplug_slot: target &hotplug_slot + * @value: LED control value + * * echo 0 > attention -- set LED OFF * echo 1 > attention -- set LED ON * echo 2 > attention -- set LED ID(identify, light is blinking) - * */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { - int retval = 0; + int rc; struct slot *slot = (struct slot *)hotplug_slot->private; - down(&rpaphp_sem); switch (value) { case 0: - retval = rpaphp_set_attention_status(slot, LED_OFF); - hotplug_slot->info->attention_status = 0; - break; case 1: - default: - retval = rpaphp_set_attention_status(slot, LED_ON); - hotplug_slot->info->attention_status = 1; - break; case 2: - retval = rpaphp_set_attention_status(slot, LED_ID); - hotplug_slot->info->attention_status = 2; + break; + default: + value = 1; break; } - up(&rpaphp_sem); - return retval; + + rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); + if (!rc) + hotplug_slot->info->attention_status = value; + + return rc; } /** * get_power_status - get power status of a slot * @hotplug_slot: slot to get status * @value: pointer to store status - * - * */ -static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - int retval; + int retval, level; struct slot *slot = (struct slot *)hotplug_slot->private; - down(&rpaphp_sem); - retval = rpaphp_get_power_status(slot, value); - up(&rpaphp_sem); + retval = rtas_get_power_level (slot->power_domain, &level); + if (!retval) + *value = level; return retval; } /** * get_attention_status - get attention LED status - * - * + * @hotplug_slot: slot to get status + * @value: pointer to store status */ -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { - int retval = 0; struct slot *slot = (struct slot *)hotplug_slot->private; - - down(&rpaphp_sem); - *value = rpaphp_get_attention_status(slot); - up(&rpaphp_sem); - return retval; + *value = slot->hotplug_slot->info->attention_status; + return 0; } -static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = (struct slot *)hotplug_slot->private; - int retval = 0; + int rc, state; - down(&rpaphp_sem); - retval = rpaphp_get_pci_adapter_status(slot, 0, value); - up(&rpaphp_sem); - return retval; + rc = rpaphp_get_sensor_state(slot, &state); + + *value = NOT_VALID; + if (rc) + return rc; + + if (state == EMPTY) + *value = EMPTY; + else if (state == PRESENT) + *value = slot->state; + + return 0; } -static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static enum pci_bus_speed get_max_bus_speed(struct slot *slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; - - down(&rpaphp_sem); + enum pci_bus_speed speed; switch (slot->type) { case 1: case 2: @@ -169,48 +141,42 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe case 4: case 5: case 6: - *value = PCI_SPEED_33MHz; /* speed for case 1-6 */ + speed = PCI_SPEED_33MHz; /* speed for case 1-6 */ break; case 7: case 8: - *value = PCI_SPEED_66MHz; + speed = PCI_SPEED_66MHz; break; case 11: case 14: - *value = PCI_SPEED_66MHz_PCIX; + speed = PCI_SPEED_66MHz_PCIX; break; case 12: case 15: - *value = PCI_SPEED_100MHz_PCIX; + speed = PCI_SPEED_100MHz_PCIX; break; case 13: case 16: - *value = PCI_SPEED_133MHz_PCIX; + speed = PCI_SPEED_133MHz_PCIX; break; default: - *value = PCI_SPEED_UNKNOWN; + speed = PCI_SPEED_UNKNOWN; break; - } - up(&rpaphp_sem); - return 0; -} -int rpaphp_remove_slot(struct slot *slot) -{ - return deregister_slot(slot); + return speed; } -static int get_children_props(struct device_node *dn, int **drc_indexes, - int **drc_names, int **drc_types, int **drc_power_domains) +static int get_children_props(struct device_node *dn, const int **drc_indexes, + const int **drc_names, const int **drc_types, + const int **drc_power_domains) { - int *indexes, *names; - int *types, *domains; + const int *indexes, *names, *types, *domains; - indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL); - names = (int *) get_property(dn, "ibm,drc-names", NULL); - types = (int *) get_property(dn, "ibm,drc-types", NULL); - domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL); + indexes = of_get_property(dn, "ibm,drc-indexes", NULL); + names = of_get_property(dn, "ibm,drc-names", NULL); + types = of_get_property(dn, "ibm,drc-types", NULL); + domains = of_get_property(dn, "ibm,drc-power-domains", NULL); if (!indexes || !names || !types || !domains) { /* Slot does not have dynamically-removable children */ @@ -237,13 +203,13 @@ static int get_children_props(struct device_node *dn, int **drc_indexes, int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, char **drc_name, char **drc_type, int *drc_power_domain) { - int *indexes, *names; - int *types, *domains; - unsigned int *my_index; + const int *indexes, *names; + const int *types, *domains; + const unsigned int *my_index; char *name_tmp, *type_tmp; int i, rc; - my_index = (int *) get_property(dn, "ibm,my-drc-index", NULL); + my_index = of_get_property(dn, "ibm,my-drc-index", NULL); if (!my_index) { /* Node isn't DLPAR/hotplug capable */ return -EINVAL; @@ -258,16 +224,16 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, type_tmp = (char *) &types[1]; /* Iterate through parent properties, looking for my-drc-index */ - for (i = 0; i < indexes[0]; i++) { + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { if ((unsigned int) indexes[i + 1] == *my_index) { if (drc_name) - *drc_name = name_tmp; + *drc_name = name_tmp; if (drc_type) *drc_type = type_tmp; if (drc_index) - *drc_index = *my_index; + *drc_index = be32_to_cpu(*my_index); if (drc_power_domain) - *drc_power_domain = domains[i+1]; + *drc_power_domain = be32_to_cpu(domains[i+1]); return 0; } name_tmp += (strlen(name_tmp) + 1); @@ -276,6 +242,7 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, return -EINVAL; } +EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); static int is_php_type(char *drc_type) { @@ -290,68 +257,102 @@ static int is_php_type(char *drc_type) return 1; } -static int is_php_dn(struct device_node *dn, int **indexes, int **names, - int **types, int **power_domains) +/** + * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0 + * @dn: target &device_node + * @indexes: passed to get_children_props() + * @names: passed to get_children_props() + * @types: returned from get_children_props() + * @power_domains: + * + * This routine will return true only if the device node is + * a hotpluggable slot. This routine will return false + * for built-in pci slots (even when the built-in slots are + * dlparable.) + */ +static int is_php_dn(struct device_node *dn, const int **indexes, + const int **names, const int **types, const int **power_domains) { - int *drc_types; + const int *drc_types; int rc; rc = get_children_props(dn, indexes, names, &drc_types, power_domains); - if (rc >= 0) { - if (is_php_type((char *) &drc_types[1])) { - *types = drc_types; - return 1; - } - } + if (rc < 0) + return 0; - return 0; + if (!is_php_type((char *) &drc_types[1])) + return 0; + + *types = drc_types; + return 1; } -/**************************************************************** - * rpaphp not only registers PCI hotplug slots(HOTPLUG), - * but also logical DR slots(EMBEDDED). - * HOTPLUG slot: An adapter can be physically added/removed. - * EMBEDDED slot: An adapter can be logically removed/added - * from/to a partition with the slot. - ***************************************************************/ +/** + * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. + * @dn: device node of slot + * + * This subroutine will register a hotpluggable slot with the + * PCI hotplug infrastructure. This routine is typically called + * during boot time, if the hotplug slots are present at boot time, + * or is called later, by the dlpar add code, if the slot is + * being dynamically added during runtime. + * + * If the device node points at an embedded (built-in) slot, this + * routine will just return without doing anything, since embedded + * slots cannot be hotplugged. + * + * To remove a slot, it suffices to call rpaphp_deregister_slot(). + */ int rpaphp_add_slot(struct device_node *dn) { struct slot *slot; int retval = 0; int i; - int *indexes, *names, *types, *power_domains; + const int *indexes, *names, *types, *power_domains; char *name, *type; - dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); + if (!dn->name || strcmp(dn->name, "pci")) + return 0; + + /* If this is not a hotplug slot, return without doing anything. */ + if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) + return 0; + + dbg("Entry %s: dn->full_name=%s\n", __func__, dn->full_name); /* register PCI devices */ - if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { - if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) - goto exit; - - name = (char *) &names[1]; - type = (char *) &types[1]; - for (i = 0; i < indexes[0]; i++, - name += (strlen(name) + 1), type += (strlen(type) + 1)) { - - if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, - power_domains[i + 1]))) { - retval = -ENOMEM; - goto exit; - } - slot->type = simple_strtoul(type, NULL, 10); - - dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", - indexes[i + 1], name, type); - - retval = register_pci_slot(slot); - } + name = (char *) &names[1]; + type = (char *) &types[1]; + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { + int index; + + index = be32_to_cpu(indexes[i + 1]); + slot = alloc_slot_struct(dn, index, name, + be32_to_cpu(power_domains[i + 1])); + if (!slot) + return -ENOMEM; + + slot->type = simple_strtoul(type, NULL, 10); + + dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", + index, name, type); + + retval = rpaphp_enable_slot(slot); + if (!retval) + retval = rpaphp_register_slot(slot); + + if (retval) + dealloc_slot_struct(slot); + + name += strlen(name) + 1; + type += strlen(type) + 1; } -exit: - dbg("%s - Exit: num_slots=%d rc[%d]\n", - __FUNCTION__, num_slots, retval); + dbg("%s - Exit: rc[%d]\n", __func__, retval); + + /* XXX FIXME: reports a failure only if last entry in loop failed */ return retval; } +EXPORT_SYMBOL_GPL(rpaphp_add_slot); static void __exit cleanup_slots(void) { @@ -361,7 +362,7 @@ static void __exit cleanup_slots(void) /* * Unregister all of our slots with the pci_hotplug subsystem, * and free up all memory that we had allocated. - * memory will be freed in release_slot callback. + * memory will be freed in release_slot callback. */ list_for_each_safe(tmp, n, &rpaphp_slot_head) { @@ -377,14 +378,10 @@ static int __init rpaphp_init(void) struct device_node *dn = NULL; info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - init_MUTEX(&rpaphp_sem); - while ((dn = of_find_node_by_type(dn, "pci"))) + while ((dn = of_find_node_by_name(dn, "pci"))) rpaphp_add_slot(dn); - if (!num_slots) - return -ENODEV; - return 0; } @@ -395,51 +392,57 @@ static void __exit rpaphp_exit(void) static int enable_slot(struct hotplug_slot *hotplug_slot) { - int retval = 0; struct slot *slot = (struct slot *)hotplug_slot->private; + int state; + int retval; - if (slot->state == CONFIGURED) { - dbg("%s: %s is already enabled\n", __FUNCTION__, slot->name); - goto exit; + if (slot->state == CONFIGURED) + return 0; + + retval = rpaphp_get_sensor_state(slot, &state); + if (retval) + return retval; + + if (state == PRESENT) { + pci_lock_rescan_remove(); + pcibios_add_pci_devices(slot->bus); + pci_unlock_rescan_remove(); + slot->state = CONFIGURED; + } else if (state == EMPTY) { + slot->state = EMPTY; + } else { + err("%s: slot[%s] is in invalid state\n", __func__, slot->name); + slot->state = NOT_VALID; + return -EINVAL; } - dbg("ENABLING SLOT %s\n", slot->name); - down(&rpaphp_sem); - retval = rpaphp_enable_pci_slot(slot); - up(&rpaphp_sem); -exit: - dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); - return retval; + slot->bus->max_bus_speed = get_max_bus_speed(slot); + return 0; } static int disable_slot(struct hotplug_slot *hotplug_slot) { - int retval = -EINVAL; struct slot *slot = (struct slot *)hotplug_slot->private; + if (slot->state == NOT_CONFIGURED) + return -EINVAL; - dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name); - - if (slot->state == NOT_CONFIGURED) { - dbg("%s: %s is already disabled\n", __FUNCTION__, slot->name); - goto exit; - } + pci_lock_rescan_remove(); + pcibios_remove_pci_devices(slot->bus); + pci_unlock_rescan_remove(); + vm_unmap_aliases(); - dbg("DISABLING SLOT %s\n", slot->name); - down(&rpaphp_sem); - retval = rpaphp_unconfig_pci_adapter(slot->bus); - up(&rpaphp_sem); slot->state = NOT_CONFIGURED; - info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, - slot->name); -exit: - dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); - return retval; + return 0; } +struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_adapter_status = get_adapter_status, +}; + module_init(rpaphp_init); module_exit(rpaphp_exit); - -EXPORT_SYMBOL_GPL(rpaphp_add_slot); -EXPORT_SYMBOL_GPL(rpaphp_remove_slot); -EXPORT_SYMBOL_GPL(rpaphp_slot_head); -EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index f7c12d7dfcf..9243f3e7a1c 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -32,59 +32,7 @@ #include "../pci.h" /* for pci_add_new_bus */ #include "rpaphp.h" -static struct pci_bus *find_bus_among_children(struct pci_bus *bus, - struct device_node *dn) -{ - struct pci_bus *child = NULL; - struct list_head *tmp; - struct device_node *busdn; - - busdn = pci_bus_to_OF_node(bus); - if (busdn == dn) - return bus; - - list_for_each(tmp, &bus->children) { - child = find_bus_among_children(pci_bus_b(tmp), dn); - if (child) - break; - } - return child; -} - -struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn) -{ - struct pci_dn *pdn = dn->data; - - if (!pdn || !pdn->phb || !pdn->phb->bus) - return NULL; - - return find_bus_among_children(pdn->phb->bus, dn); -} -EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus); - -int rpaphp_claim_resource(struct pci_dev *dev, int resource) -{ - struct resource *res = &dev->resource[resource]; - struct resource *root = pci_find_parent_resource(dev, res); - char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; - int err = -EINVAL; - - if (root != NULL) { - err = request_resource(root, res); - } - - if (err) { - err("PCI: %s region %d of %s %s [%lx:%lx]\n", - root ? "Address space collision on" : - "No parent found for", - resource, dtype, pci_name(dev), res->start, res->end); - } - return err; -} - -EXPORT_SYMBOL_GPL(rpaphp_claim_resource); - -static int rpaphp_get_sensor_state(struct slot *slot, int *state) +int rpaphp_get_sensor_state(struct slot *slot, int *state) { int rc; int setlevel; @@ -94,373 +42,94 @@ static int rpaphp_get_sensor_state(struct slot *slot, int *state) if (rc < 0) { if (rc == -EFAULT || rc == -EEXIST) { dbg("%s: slot must be power up to get sensor-state\n", - __FUNCTION__); + __func__); - /* some slots have to be powered up + /* some slots have to be powered up * before get-sensor will succeed. */ rc = rtas_set_power_level(slot->power_domain, POWER_ON, &setlevel); if (rc < 0) { dbg("%s: power on slot[%s] failed rc=%d.\n", - __FUNCTION__, slot->name, rc); + __func__, slot->name, rc); } else { rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state); } } else if (rc == -ENODEV) - info("%s: slot is unusable\n", __FUNCTION__); + info("%s: slot is unusable\n", __func__); else - err("%s failed to get sensor state\n", __FUNCTION__); + err("%s failed to get sensor state\n", __func__); } return rc; } /** - * get_pci_adapter_status - get the status of a slot - * - * 0-- slot is empty - * 1-- adapter is configured - * 2-- adapter is not configured - * 3-- not valid + * rpaphp_enable_slot - record slot state, config pci device + * @slot: target &slot + * + * Initialize values in the slot, and the hotplug_slot info + * structures to indicate if there is a pci card plugged into + * the slot. If the slot is not empty, run the pcibios routine + * to get pcibios stuff correctly set up. */ -int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) +int rpaphp_enable_slot(struct slot *slot) { + int rc, level, state; struct pci_bus *bus; - int state, rc; - - *value = NOT_VALID; - rc = rpaphp_get_sensor_state(slot, &state); - if (rc) - goto exit; - - if (state == EMPTY) - *value = EMPTY; - else if (state == PRESENT) { - if (!is_init) { - /* at run-time slot->state can be changed by */ - /* config/unconfig adapter */ - *value = slot->state; - } else { - bus = rpaphp_find_pci_bus(slot->dn); - if (bus && !list_empty(&bus->devices)) - *value = CONFIGURED; - else - *value = NOT_CONFIGURED; - } - } -exit: - return rc; -} - -/* Must be called before pci_bus_add_devices */ -static void -rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) -{ - struct pci_dev *dev; + struct hotplug_slot_info *info = slot->hotplug_slot->info; - list_for_each_entry(dev, &bus->devices, bus_list) { - /* - * Skip already-present devices (which are on the - * global device list.) - */ - if (list_empty(&dev->global_list)) { - int i; - - /* Need to setup IOMMU tables */ - ppc_md.iommu_dev_setup(dev); - - if(fix_bus) - pcibios_fixup_device_resources(dev, bus); - pci_read_irq_line(dev); - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - - if (r->parent || !r->start || !r->flags) - continue; - rpaphp_claim_resource(dev, i); - } - } - } -} - -static int rpaphp_pci_config_bridge(struct pci_dev *dev) -{ - u8 sec_busno; - struct pci_bus *child_bus; - struct pci_dev *child_dev; - - dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev)); - - /* get busno of downstream bus */ - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); - - /* add to children of PCI bridge dev->bus */ - child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); - if (!child_bus) { - err("%s: could not add second bus\n", __FUNCTION__); - return -EIO; - } - sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); - /* do pci_scan_child_bus */ - pci_scan_child_bus(child_bus); - - list_for_each_entry(child_dev, &child_bus->devices, bus_list) { - eeh_add_device_late(child_dev); - } - - /* fixup new pci devices without touching bus struct */ - rpaphp_fixup_new_pci_devices(child_bus, 0); - - /* Make the discovered devices available */ - pci_bus_add_devices(child_bus); - return 0; -} - -/***************************************************************************** - rpaphp_pci_config_slot() will configure all devices under the - given slot->dn and return the the first pci_dev. - *****************************************************************************/ -static struct pci_dev * -rpaphp_pci_config_slot(struct pci_bus *bus) -{ - struct device_node *dn = pci_bus_to_OF_node(bus); - struct pci_dev *dev = NULL; - int slotno; - int num; - - dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); - if (!dn || !dn->child) - return NULL; - - slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); - - /* pci_scan_slot should find all children */ - num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); - if (num) { - rpaphp_fixup_new_pci_devices(bus, 1); - pci_bus_add_devices(bus); - } - if (list_empty(&bus->devices)) { - err("%s: No new device found\n", __FUNCTION__); - return NULL; - } - list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - rpaphp_pci_config_bridge(dev); - } - - return dev; -} - -static void enable_eeh(struct device_node *dn) -{ - struct device_node *sib; + info->adapter_status = NOT_VALID; + slot->state = EMPTY; - for (sib = dn->child; sib; sib = sib->sibling) - enable_eeh(sib); - eeh_add_device_early(dn); - return; - -} - -static void print_slot_pci_funcs(struct pci_bus *bus) -{ - struct device_node *dn; - struct pci_dev *dev; - - dn = pci_bus_to_OF_node(bus); - if (!dn) - return; - - dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); - list_for_each_entry (dev, &bus->devices, bus_list) - dbg("\t%s\n", pci_name(dev)); - return; -} - -int rpaphp_config_pci_adapter(struct pci_bus *bus) -{ - struct device_node *dn = pci_bus_to_OF_node(bus); - struct pci_dev *dev; - int rc = -ENODEV; - - dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name); - if (!dn) - goto exit; - - enable_eeh(dn); - dev = rpaphp_pci_config_slot(bus); - if (!dev) { - err("%s: can't find any devices.\n", __FUNCTION__); - goto exit; - } - print_slot_pci_funcs(bus); - rc = 0; -exit: - dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); - return rc; -} -EXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter); - -static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) -{ - eeh_remove_device(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *bus = dev->subordinate; - struct list_head *ln; - if (!bus) - return; - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev) - rpaphp_eeh_remove_bus_device(pdev); - } - - } - return; -} - -int rpaphp_unconfig_pci_adapter(struct pci_bus *bus) -{ - struct pci_dev *dev, *tmp; - - list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { - rpaphp_eeh_remove_bus_device(dev); - pci_remove_bus_device(dev); - } - return 0; -} - -static int setup_pci_hotplug_slot_info(struct slot *slot) -{ - dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", - __FUNCTION__); - rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status); - rpaphp_get_pci_adapter_status(slot, 1, - &slot->hotplug_slot->info-> - adapter_status); - if (slot->hotplug_slot->info->adapter_status == NOT_VALID) { - err("%s: NOT_VALID: skip dn->full_name=%s\n", - __FUNCTION__, slot->dn->full_name); - return -EINVAL; - } - return 0; -} - -static void set_slot_name(struct slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *bridge; - - bridge = bus->self; - if (bridge) - strcpy(slot->name, pci_name(bridge)); - else - sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), - bus->number); -} + /* Find out if the power is turned on for the slot */ + rc = rtas_get_power_level(slot->power_domain, &level); + if (rc) + return rc; + info->power_status = level; -static int setup_pci_slot(struct slot *slot) -{ - struct device_node *dn = slot->dn; - struct pci_bus *bus; + /* Figure out if there is an adapter in the slot */ + rc = rpaphp_get_sensor_state(slot, &state); + if (rc) + return rc; - BUG_ON(!dn); - bus = rpaphp_find_pci_bus(dn); + bus = pcibios_find_pci_bus(slot->dn); if (!bus) { - err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); - goto exit_rc; + err("%s: no pci_bus for dn %s\n", __func__, slot->dn->full_name); + return -EINVAL; } + info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; - set_slot_name(slot); - /* find slot's pci_dev if it's not empty */ - if (slot->hotplug_slot->info->adapter_status == EMPTY) { - slot->state = EMPTY; /* slot is empty */ - } else { - /* slot is occupied */ - if (!dn->child) { - /* non-empty slot has to have child */ - err("%s: slot[%s]'s device_node doesn't have child for adapter\n", - __FUNCTION__, slot->name); - goto exit_rc; + /* if there's an adapter in the slot, go add the pci devices */ + if (state == PRESENT) { + info->adapter_status = NOT_CONFIGURED; + slot->state = NOT_CONFIGURED; + + /* non-empty slot has to have child */ + if (!slot->dn->child) { + err("%s: slot[%s]'s device_node doesn't have child for adapter\n", + __func__, slot->name); + return -EINVAL; } - if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { - dbg("%s CONFIGURING pci adapter in slot[%s]\n", - __FUNCTION__, slot->name); - if (rpaphp_config_pci_adapter(slot->bus)) { - err("%s: CONFIG pci adapter failed\n", __FUNCTION__); - goto exit_rc; - } + if (list_empty(&bus->devices)) + pcibios_add_pci_devices(bus); - } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { - err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", - __FUNCTION__, slot->name); - goto exit_rc; - } - print_slot_pci_funcs(slot->bus); - if (!list_empty(slot->pci_devs)) { + if (!list_empty(&bus->devices)) { + info->adapter_status = CONFIGURED; slot->state = CONFIGURED; - } else { - /* DLPAR add as opposed to - * boot time */ - slot->state = NOT_CONFIGURED; } - } - return 0; -exit_rc: - dealloc_slot_struct(slot); - return -EINVAL; -} - -int register_pci_slot(struct slot *slot) -{ - int rc = -EINVAL; - - if (setup_pci_hotplug_slot_info(slot)) - goto exit_rc; - if (setup_pci_slot(slot)) - goto exit_rc; - rc = register_slot(slot); -exit_rc: - return rc; -} - -int rpaphp_enable_pci_slot(struct slot *slot) -{ - int retval = 0, state; - retval = rpaphp_get_sensor_state(slot, &state); - if (retval) - goto exit; - dbg("%s: sensor state[%d]\n", __FUNCTION__, state); - /* if slot is not empty, enable the adapter */ - if (state == PRESENT) { - dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name); - retval = rpaphp_config_pci_adapter(slot->bus); - if (!retval) { - slot->state = CONFIGURED; - dbg("%s: PCI devices in slot[%s] has been configured\n", - __FUNCTION__, slot->name); - } else { - slot->state = NOT_CONFIGURED; - dbg("%s: no pci_dev struct for adapter in slot[%s]\n", - __FUNCTION__, slot->name); + if (rpaphp_debug) { + struct pci_dev *dev; + dbg("%s: pci_devs of slot[%s]\n", __func__, slot->dn->full_name); + list_for_each_entry (dev, &bus->devices, bus_list) + dbg("\t%s\n", pci_name(dev)); } - } else if (state == EMPTY) { - dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name); - slot->state = EMPTY; - } else { - err("%s: slot[%s] is in invalid state\n", __FUNCTION__, - slot->name); - slot->state = NOT_VALID; - retval = -EINVAL; } -exit: - dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); - return retval; + + return 0; } diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index daa89ae5712..a6082cc263f 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -1,5 +1,5 @@ /* - * RPA Virtual I/O device functions + * RPA Virtual I/O device functions * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com> * * All rights reserved. @@ -24,7 +24,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/pci.h> #include <linux/string.h> @@ -33,89 +32,48 @@ #include <asm/rtas.h> #include "rpaphp.h" -static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) -{ - char *value; - int retval = -ENOENT; - struct slot *slot = (struct slot *)php_slot->private; - - if (!slot) - return retval; - - value = slot->location; - retval = sprintf (buf, "%s\n", value); - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_location = { - .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, - .show = location_read_file, -}; - -static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot) -{ - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr); -} - -static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot) -{ - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr); -} - /* free up the memory used by a slot */ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = (struct slot *) hotplug_slot->private; - dealloc_slot_struct(slot); } void dealloc_slot_struct(struct slot *slot) { kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); + kfree(slot->name); kfree(slot->hotplug_slot); kfree(slot); - return; } -struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, - int power_domain) +struct slot *alloc_slot_struct(struct device_node *dn, + int drc_index, char *drc_name, int power_domain) { struct slot *slot; - - slot = kmalloc(sizeof (struct slot), GFP_KERNEL); + + slot = kzalloc(sizeof(struct slot), GFP_KERNEL); if (!slot) goto error_nomem; - memset(slot, 0, sizeof (struct slot)); - slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); + slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); if (!slot->hotplug_slot) - goto error_slot; - memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); - slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info), + goto error_slot; + slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); if (!slot->hotplug_slot->info) goto error_hpslot; - memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); - slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL); - if (!slot->hotplug_slot->name) - goto error_info; - slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); - if (!slot->location) - goto error_name; - slot->name = slot->hotplug_slot->name; + slot->name = kstrdup(drc_name, GFP_KERNEL); + if (!slot->name) + goto error_info; slot->dn = dn; slot->index = drc_index; - strcpy(slot->location, drc_name); slot->power_domain = power_domain; slot->hotplug_slot->private = slot; slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; slot->hotplug_slot->release = &rpaphp_release_slot; - + return (slot); -error_name: - kfree(slot->hotplug_slot->name); error_info: kfree(slot->hotplug_slot->info); error_hpslot: @@ -128,99 +86,62 @@ error_nomem: static int is_registered(struct slot *slot) { - struct slot *tmp_slot; + struct slot *tmp_slot; list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { if (!strcmp(tmp_slot->name, slot->name)) return 1; - } + } return 0; } -int deregister_slot(struct slot *slot) +int rpaphp_deregister_slot(struct slot *slot) { int retval = 0; struct hotplug_slot *php_slot = slot->hotplug_slot; dbg("%s - Entry: deregistering slot=%s\n", - __FUNCTION__, slot->name); + __func__, slot->name); list_del(&slot->rpaphp_slot_list); - - /* remove "phy_location" file */ - rpaphp_sysfs_remove_attr_location(php_slot); retval = pci_hp_deregister(php_slot); if (retval) err("Problem unregistering a slot %s\n", slot->name); - else - num_slots--; - dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); + dbg("%s - Exit: rc[%d]\n", __func__, retval); return retval; } +EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); -int register_slot(struct slot *slot) +int rpaphp_register_slot(struct slot *slot) { + struct hotplug_slot *php_slot = slot->hotplug_slot; int retval; + int slotno; - dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", - __FUNCTION__, slot->dn->full_name, slot->index, slot->name, + dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", + __func__, slot->dn->full_name, slot->index, slot->name, slot->power_domain, slot->type); + /* should not try to register the same slot twice */ - if (is_registered(slot)) { /* should't be here */ - err("register_slot: slot[%s] is already registered\n", slot->name); - rpaphp_release_slot(slot->hotplug_slot); + if (is_registered(slot)) { + err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); return -EAGAIN; - } - retval = pci_hp_register(slot->hotplug_slot); + } + + if (slot->dn->child) + slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); + else + slotno = -1; + retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name); if (retval) { err("pci_hp_register failed with error %d\n", retval); - rpaphp_release_slot(slot->hotplug_slot); return retval; } - - /* create "phy_locatoin" file */ - rpaphp_sysfs_add_attr_location(slot->hotplug_slot); /* add slot to our internal list */ - dbg("%s adding slot[%s] to rpaphp_slot_list\n", - __FUNCTION__, slot->name); - list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); - info("Slot [%s](PCI location=%s) registered\n", slot->name, - slot->location); - num_slots++; + info("Slot [%s] registered\n", slot->name); return 0; } - -int rpaphp_get_power_status(struct slot *slot, u8 * value) -{ - int rc = 0, level; - - rc = rtas_get_power_level(slot->power_domain, &level); - if (rc < 0) { - err("failed to get power-level for slot(%s), rc=0x%x\n", - slot->location, rc); - return rc; - } - - dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", - __FUNCTION__, slot->name, slot->power_domain, level); - *value = level; - - return rc; -} - -int rpaphp_set_attention_status(struct slot *slot, u8 status) -{ - int rc; - - /* status: LED_OFF or LED_ON */ - rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); - if (rc < 0) - err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n", - slot->name, slot->location, slot->index, status, rc); - - return rc; -} diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c new file mode 100644 index 00000000000..d1332d2f873 --- /dev/null +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -0,0 +1,214 @@ +/* + * PCI Hot Plug Controller Driver for System z + * + * Copyright 2012 IBM Corp. + * + * Author(s): + * Jan Glauber <jang@linux.vnet.ibm.com> + */ + +#define COMPONENT "zPCI hpc" +#define pr_fmt(fmt) COMPONENT ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/pci_hotplug.h> +#include <asm/pci_debug.h> +#include <asm/sclp.h> + +#define SLOT_NAME_SIZE 10 +static LIST_HEAD(s390_hotplug_slot_list); + +MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com"); +MODULE_DESCRIPTION("Hot Plug PCI Controller for System z"); +MODULE_LICENSE("GPL"); + +static int zpci_fn_configured(enum zpci_state state) +{ + return state == ZPCI_FN_STATE_CONFIGURED || + state == ZPCI_FN_STATE_ONLINE; +} + +/* + * struct slot - slot information for each *physical* slot + */ +struct slot { + struct list_head slot_list; + struct hotplug_slot *hotplug_slot; + struct zpci_dev *zdev; +}; + +static inline int slot_configure(struct slot *slot) +{ + int ret = sclp_pci_configure(slot->zdev->fid); + + zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); + if (!ret) + slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; + + return ret; +} + +static inline int slot_deconfigure(struct slot *slot) +{ + int ret = sclp_pci_deconfigure(slot->zdev->fid); + + zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); + if (!ret) + slot->zdev->state = ZPCI_FN_STATE_STANDBY; + + return ret; +} + +static int enable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + int rc; + + if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) + return -EIO; + + rc = slot_configure(slot); + if (rc) + return rc; + + rc = zpci_enable_device(slot->zdev); + if (rc) + goto out_deconfigure; + + pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); + pci_lock_rescan_remove(); + pci_bus_add_devices(slot->zdev->bus); + pci_unlock_rescan_remove(); + + return rc; + +out_deconfigure: + slot_deconfigure(slot); + return rc; +} + +static int disable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + int rc; + + if (!zpci_fn_configured(slot->zdev->state)) + return -EIO; + + if (slot->zdev->pdev) + pci_stop_and_remove_bus_device_locked(slot->zdev->pdev); + + rc = zpci_disable_device(slot->zdev); + if (rc) + return rc; + + return slot_deconfigure(slot); +} + +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = hotplug_slot->private; + + switch (slot->zdev->state) { + case ZPCI_FN_STATE_STANDBY: + *value = 0; + break; + default: + *value = 1; + break; + } + return 0; +} + +static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + /* if the slot exits it always contains a function */ + *value = 1; + return 0; +} + +static void release_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot); + kfree(slot); +} + +static struct hotplug_slot_ops s390_hotplug_slot_ops = { + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .get_power_status = get_power_status, + .get_adapter_status = get_adapter_status, +}; + +int zpci_init_slot(struct zpci_dev *zdev) +{ + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char name[SLOT_NAME_SIZE]; + struct slot *slot; + int rc; + + if (!zdev) + return 0; + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + goto error; + + hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) + goto error_hp; + hotplug_slot->private = slot; + + slot->hotplug_slot = hotplug_slot; + slot->zdev = zdev; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + goto error_info; + hotplug_slot->info = info; + + hotplug_slot->ops = &s390_hotplug_slot_ops; + hotplug_slot->release = &release_slot; + + get_power_status(hotplug_slot, &info->power_status); + get_adapter_status(hotplug_slot, &info->adapter_status); + + snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); + rc = pci_hp_register(slot->hotplug_slot, zdev->bus, + ZPCI_DEVFN, name); + if (rc) + goto error_reg; + + list_add(&slot->slot_list, &s390_hotplug_slot_list); + return 0; + +error_reg: + kfree(info); +error_info: + kfree(hotplug_slot); +error_hp: + kfree(slot); +error: + return -ENOMEM; +} + +void zpci_exit_slot(struct zpci_dev *zdev) +{ + struct list_head *tmp, *n; + struct slot *slot; + + list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if (slot->zdev != zdev) + continue; + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + } +} diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index a32ae82e592..bada2099987 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -3,43 +3,52 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved. * * This work was based on the 2.4/2.6 kernel development by Dick Reigner. * Work to add BIOS PROM support was completed by Mike Habeck. */ +#include <linux/acpi.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/proc_fs.h> +#include <linux/slab.h> #include <linux/types.h> +#include <linux/mutex.h> #include <asm/sn/addrs.h> +#include <asm/sn/geo.h> #include <asm/sn/l1.h> #include <asm/sn/module.h> #include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> +#include <asm/sn/sn_feature_sets.h> #include <asm/sn/sn_sal.h> #include <asm/sn/types.h> +#include <asm/sn/acpi.h> #include "../pci.h" -#include "pci_hotplug.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); -#define PCIIO_ASIC_TYPE_TIOCA 4 + +/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */ #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ #define PCI_L1_ERR 7 /* L1 console command error */ #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ + + +#define PCIIO_ASIC_TYPE_TIOCA 4 #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ -#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ #define SN_SLOT_NAME_SIZE 33 /* size of name string */ /* internal list head */ @@ -75,19 +84,17 @@ static int disable_slot(struct hotplug_slot *slot); static inline int get_power_status(struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops sn_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .get_power_status = get_power_status, }; -static DECLARE_MUTEX(sn_hotplug_sem); +static DEFINE_MUTEX(sn_hotplug_mutex); -static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, - char *buf) +static ssize_t path_show(struct pci_slot *pci_slot, char *buf) { int retval = -ENOENT; - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = pci_slot->hotplug->private; if (!slot) return retval; @@ -96,13 +103,12 @@ static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, return retval; } -static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); +static struct pci_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); @@ -110,12 +116,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; @@ -124,23 +132,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: @@ -152,7 +160,8 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus) } static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, - struct pci_bus *pci_bus, int device) + struct pci_bus *pci_bus, int device, + char *name) { struct pcibus_info *pcibus_info; struct slot *slot; @@ -164,61 +173,39 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, return -ENOMEM; bss_hotplug_slot->private = slot; - bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL); - if (!bss_hotplug_slot->name) { - kfree(bss_hotplug_slot->private); - return -ENOMEM; - } - slot->device_num = device; slot->pci_bus = pci_bus; - sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", + sprintf(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); return 0; } -static struct hotplug_slot * sn_hp_destroy(void) +static struct hotplug_slot *sn_hp_destroy(void) { struct slot *slot; + struct pci_slot *pci_slot; struct hotplug_slot *bss_hotplug_slot = NULL; list_for_each_entry(slot, &sn_hp_list, hp_list) { bss_hotplug_slot = slot->hotplug_slot; + pci_slot = bss_hotplug_slot->pci_slot; list_del(&((struct slot *)bss_hotplug_slot->private)-> hp_list); - sysfs_remove_file(&bss_hotplug_slot->kobj, + sysfs_remove_file(&pci_slot->kobj, &sn_slot_path_attr.attr); break; } return bss_hotplug_slot; } -static void sn_bus_alloc_data(struct pci_dev *dev) -{ - struct pci_bus *subordinate_bus; - struct pci_dev *child; - - sn_pci_fixup_slot(dev); - - /* Recursively sets up the sn_irq_info structs */ - if (dev->subordinate) { - subordinate_bus = dev->subordinate; - list_for_each_entry(child, &subordinate_bus->devices, bus_list) - sn_bus_alloc_data(child); - } -} - static void sn_bus_free_data(struct pci_dev *dev) { struct pci_bus *subordinate_bus; @@ -230,11 +217,18 @@ static void sn_bus_free_data(struct pci_dev *dev) list_for_each_entry(child, &subordinate_bus->devices, bus_list) sn_bus_free_data(child); } + /* + * Some drivers may use dma accesses during the + * driver remove function. We release the sysdata + * areas after the driver remove functions have + * been called. + */ + sn_bus_store_sysdata(dev); sn_pci_unfixup_slot(dev); } static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, - int device_num) + int device_num, char **ssdt) { struct slot *slot = bss_hotplug_slot->private; struct pcibus_info *pcibus_info; @@ -247,23 +241,22 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, * Power-on and initialize the slot in the SN * PCI infrastructure. */ - rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); + rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt); + if (rc == PCI_SLOT_ALREADY_UP) { - dev_dbg(slot->pci_bus->self, "is already active\n"); + dev_dbg(&slot->pci_bus->self->dev, "is already active\n"); return 1; /* return 1 to user */ } if (rc == PCI_L1_ERR) { - dev_dbg(slot->pci_bus->self, - "L1 failure %d with message: %s", + dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message: %s", resp.resp_sub_errno, resp.resp_l1_msg); return -EPERM; } if (rc) { - dev_dbg(slot->pci_bus->self, - "insert failed with error %d sub-error %d\n", + dev_dbg(&slot->pci_bus->self->dev, "insert failed with error %d sub-error %d\n", rc, resp.resp_sub_errno); return -EIO; } @@ -288,26 +281,23 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_SLOT_ALREADY_DOWN)) { - dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); + dev_dbg(&slot->pci_bus->self->dev, "Slot %s already inactive\n", slot->physical_path); return 1; /* return 1 to user */ } if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) { - dev_dbg(slot->pci_bus->self, - "Cannot remove last 33MHz card\n"); + dev_dbg(&slot->pci_bus->self->dev, "Cannot remove last 33MHz card\n"); return -EPERM; } if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) { - dev_dbg(slot->pci_bus->self, - "L1 failure %d with message \n%s\n", + dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message \n%s\n", resp.resp_sub_errno, resp.resp_l1_msg); return -EPERM; } if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) { - dev_dbg(slot->pci_bus->self, - "remove failed with error %d sub-error %d\n", + dev_dbg(&slot->pci_bus->self->dev, "remove failed with error %d sub-error %d\n", rc, resp.resp_sub_errno); return -EIO; } @@ -318,91 +308,164 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, if ((action == PCI_REQ_SLOT_DISABLE) && !rc) { pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); pcibus_info->pbi_enabled_devices &= ~(1 << device_num); - dev_dbg(slot->pci_bus->self, "remove successful\n"); + dev_dbg(&slot->pci_bus->self->dev, "remove successful\n"); return 0; } if ((action == PCI_REQ_SLOT_DISABLE) && rc) { - dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); + dev_dbg(&slot->pci_bus->self->dev,"remove failed rc = %d\n", rc); } return rc; } +/* + * Power up and configure the slot via a SAL call to PROM. + * Scan slot (and any children), do any platform specific fixup, + * and find device driver. + */ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) { struct slot *slot = bss_hotplug_slot->private; struct pci_bus *new_bus = NULL; struct pci_dev *dev; - int func, num_funcs; + int num_funcs; int new_ppb = 0; int rc; + char *ssdt = NULL; + void pcibios_fixup_device_resources(struct pci_dev *); /* Serialize the Linux PCI infrastructure */ - down(&sn_hotplug_sem); + mutex_lock(&sn_hotplug_mutex); /* * Power-on and initialize the slot in the SN - * PCI infrastructure. + * PCI infrastructure. Also, retrieve the ACPI SSDT + * table for the slot (if ACPI capable PROM). */ - rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); + rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt); if (rc) { - up(&sn_hotplug_sem); + mutex_unlock(&sn_hotplug_mutex); return rc; } + if (ssdt) + ssdt = __va(ssdt); + /* Add the new SSDT for the slot to the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + acpi_status ret; + + ret = acpi_load_table((struct acpi_table_header *)ssdt); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n", + __func__, ret); + /* try to continue on */ + } + } + num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num + 1, 0)); if (!num_funcs) { - dev_dbg(slot->pci_bus->self, "no device in slot\n"); - up(&sn_hotplug_sem); + dev_dbg(&slot->pci_bus->self->dev, "no device in slot\n"); + mutex_unlock(&sn_hotplug_mutex); return -ENODEV; } - sn_pci_controller_fixup(pci_domain_nr(slot->pci_bus), - slot->pci_bus->number, - slot->pci_bus); /* * Map SN resources for all functions on the card * to the Linux PCI interface and tell the drivers * about them. */ - for (func = 0; func < num_funcs; func++) { - dev = pci_get_slot(slot->pci_bus, - PCI_DEVFN(slot->device_num + 1, - PCI_FUNC(func))); - if (dev) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - unsigned char sec_bus; - pci_read_config_byte(dev, PCI_SECONDARY_BUS, - &sec_bus); - new_bus = pci_add_new_bus(dev->bus, dev, - sec_bus); - pci_scan_child_bus(new_bus); - sn_pci_controller_fixup(pci_domain_nr(new_bus), - new_bus->number, - new_bus); + list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != slot->device_num + 1) + continue; + + /* Need to do slot fixup on PPB before fixup of children + * (PPB's pcidev_info needs to be in pcidev_info list + * before child's SN_PCIDEV_INFO() call to setup + * pdi_host_pcidev_info). + */ + pcibios_fixup_device_resources(dev); + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev); + else + sn_io_slot_fixup(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_hp_add_bridge(dev); + if (dev->subordinate) { + new_bus = dev->subordinate; new_ppb = 1; } - sn_bus_alloc_data(dev); - pci_dev_put(dev); } } + /* + * Add the slot's devices to the ACPI infrastructure */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + unsigned long long adr; + struct acpi_device *pdevice; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion); + + if (acpi_bus_get_device(phandle, &pdevice)) { + dev_dbg(&slot->pci_bus->self->dev, "no parent device, assuming NULL\n"); + pdevice = NULL; + } + + acpi_scan_lock_acquire(); + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR, + NULL, &adr); + + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + + ret = acpi_bus_scan(chandle); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_bus_scan failed (0x%x) for slot %d func %d\n", + __func__, ret, (int)(adr>>16), + (int)(adr&0xffff)); + /* try to continue on */ + } + } + } + acpi_scan_lock_release(); + } + + pci_lock_rescan_remove(); + /* Call the driver for the new device */ pci_bus_add_devices(slot->pci_bus); /* Call the drivers for the new devices subordinate to PPB */ if (new_ppb) pci_bus_add_devices(new_bus); - up(&sn_hotplug_sem); + pci_unlock_rescan_remove(); + mutex_unlock(&sn_hotplug_mutex); if (rc == 0) - dev_dbg(slot->pci_bus->self, - "insert operation successful\n"); + dev_dbg(&slot->pci_bus->self->dev, "insert operation successful\n"); else - dev_dbg(slot->pci_bus->self, - "insert operation failed rc = %d\n", rc); + dev_dbg(&slot->pci_bus->self->dev, "insert operation failed rc = %d\n", rc); return rc; } @@ -410,12 +473,12 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) static int disable_slot(struct hotplug_slot *bss_hotplug_slot) { struct slot *slot = bss_hotplug_slot->private; - struct pci_dev *dev; - int func; + struct pci_dev *dev, *temp; int rc; + acpi_owner_id ssdt_id = 0; /* Acquire update access to the bus */ - down(&sn_hotplug_sem); + mutex_lock(&sn_hotplug_mutex); /* is it okay to bring this slot down? */ rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, @@ -423,22 +486,74 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) if (rc) goto leaving; + /* free the ACPI resources for the slot */ + if (SN_ACPI_BASE_SUPPORT() && + PCI_CONTROLLER(slot->pci_bus)->companion) { + unsigned long long adr; + struct acpi_device *device; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + /* Get the rootbus node pointer */ + phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion); + + acpi_scan_lock_acquire(); + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, + METHOD_NAME__ADR, + NULL, &adr); + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + /* retain the owner id */ + acpi_get_id(chandle, &ssdt_id); + + ret = acpi_bus_get_device(chandle, + &device); + if (ACPI_SUCCESS(ret)) + acpi_bus_trim(device); + } + } + acpi_scan_lock_release(); + } + + pci_lock_rescan_remove(); /* Free the SN resources assigned to the Linux device.*/ - for (func = 0; func < 8; func++) { - dev = pci_get_slot(slot->pci_bus, - PCI_DEVFN(slot->device_num + 1, - PCI_FUNC(func))); - if (dev) { - /* - * Some drivers may use dma accesses during the - * driver remove function. We release the sysdata - * areas after the driver remove functions have - * been called. - */ - sn_bus_store_sysdata(dev); - sn_bus_free_data(dev); - pci_remove_bus_device(dev); - pci_dev_put(dev); + list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != slot->device_num + 1) + continue; + + pci_dev_get(dev); + sn_bus_free_data(dev); + pci_stop_and_remove_bus_device(dev); + pci_dev_put(dev); + } + pci_unlock_rescan_remove(); + + /* Remove the SSDT for the slot from the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { + acpi_status ret; + ret = acpi_unload_table_id(ssdt_id); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_unload_table_id failed (0x%x) for id %d\n", + __func__, ret, ssdt_id); + /* try to continue on */ } } @@ -450,7 +565,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) PCI_REQ_SLOT_DISABLE); leaving: /* Release the bus lock */ - up(&sn_hotplug_sem); + mutex_unlock(&sn_hotplug_mutex); return rc; } @@ -460,18 +575,19 @@ 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); - down(&sn_hotplug_sem); - *value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); - up(&sn_hotplug_sem); + mutex_lock(&sn_hotplug_mutex); + power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); + *value = power ? 1 : 0; + mutex_unlock(&sn_hotplug_mutex); return 0; } static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) { kfree(bss_hotplug_slot->info); - kfree(bss_hotplug_slot->name); kfree(bss_hotplug_slot->private); kfree(bss_hotplug_slot); } @@ -479,7 +595,9 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) static int sn_hotplug_slot_register(struct pci_bus *pci_bus) { int device; + struct pci_slot *pci_slot; struct hotplug_slot *bss_hotplug_slot; + char name[SN_SLOT_NAME_SIZE]; int rc = 0; /* @@ -507,33 +625,33 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) } if (sn_hp_slot_private_alloc(bss_hotplug_slot, - pci_bus, device)) { + pci_bus, device, name)) { rc = -ENOMEM; goto alloc_err; } - bss_hotplug_slot->ops = &sn_hotplug_slot_ops; bss_hotplug_slot->release = &sn_release_slot; - rc = pci_hp_register(bss_hotplug_slot); + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name); if (rc) goto register_err; - rc = sysfs_create_file(&bss_hotplug_slot->kobj, + pci_slot = bss_hotplug_slot->pci_slot; + rc = sysfs_create_file(&pci_slot->kobj, &sn_slot_path_attr.attr); if (rc) goto register_err; } - dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); + dev_dbg(&pci_bus->self->dev, "Registered bus with hotplug\n"); return rc; register_err: - dev_dbg(pci_bus->self, "bus failed to register with err = %d\n", - rc); + dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n", + rc); alloc_err: if (rc == -ENOMEM) - dev_dbg(pci_bus->self, "Memory allocation error\n"); + dev_dbg(&pci_bus->self->dev, "Memory allocation error\n"); /* destroy THIS element */ if (bss_hotplug_slot) @@ -546,15 +664,15 @@ alloc_err: return rc; } -static int sn_pci_hotplug_init(void) +static int __init sn_pci_hotplug_init(void) { struct pci_bus *pci_bus = NULL; 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", - __FUNCTION__); + if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) { + printk(KERN_ERR "%s: PROM version does not support hotplug.\n", + __func__); return -EPERM; } @@ -566,10 +684,10 @@ static int sn_pci_hotplug_init(void) rc = sn_pci_bus_valid(pci_bus); if (rc != 1) { - dev_dbg(pci_bus->self, "not a valid hotplug bus\n"); + dev_dbg(&pci_bus->self->dev, "not a valid hotplug bus\n"); continue; } - dev_dbg(pci_bus->self, "valid hotplug bus\n"); + dev_dbg(&pci_bus->self->dev, "valid hotplug bus\n"); rc = sn_hotplug_slot_register(pci_bus); if (!rc) { @@ -583,7 +701,7 @@ static int sn_pci_hotplug_init(void) return registered == 1 ? 0 : -ENODEV; } -static void sn_pci_hotplug_exit(void) +static void __exit sn_pci_hotplug_exit(void) { struct hotplug_slot *bss_hotplug_slot; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 08ad26a0cae..5897d516427 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -31,10 +31,11 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #include <linux/delay.h> #include <linux/sched.h> /* signal_pending(), struct timer_list */ - -#include "pci_hotplug.h" +#include <linux/mutex.h> +#include <linux/workqueue.h> #if !defined(MODULE) #define MY_NAME "shpchp" @@ -42,20 +43,38 @@ #define MY_NAME THIS_MODULE->name #endif -extern int shpchp_poll_mode; +extern bool shpchp_poll_mode; extern int shpchp_poll_time; -extern int shpchp_debug; +extern bool shpchp_debug; + +#define dbg(format, arg...) \ +do { \ + if (shpchp_debug) \ + printk(KERN_DEBUG "%s: " format, MY_NAME , ## 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 ctrl_dbg(ctrl, format, arg...) \ + do { \ + if (shpchp_debug) \ + dev_printk(KERN_DEBUG, &ctrl->pci_dev->dev, \ + format, ## arg); \ + } while (0) +#define ctrl_err(ctrl, format, arg...) \ + dev_err(&ctrl->pci_dev->dev, format, ## arg) +#define ctrl_info(ctrl, format, arg...) \ + dev_info(&ctrl->pci_dev->dev, format, ## arg) +#define ctrl_warn(ctrl, format, arg...) \ + dev_warn(&ctrl->pci_dev->dev, format, ## arg) -/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ -#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## 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 SLOT_MAGIC 0x67267321 +#define SLOT_NAME_SIZE 10 struct slot { - u32 magic; - struct slot *next; u8 bus; u8 device; u16 status; @@ -64,51 +83,62 @@ struct slot { u8 state; u8 presence_save; u8 pwr_save; - struct timer_list task_event; - u8 hp_slot; struct controller *ctrl; struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; + struct delayed_work work; /* work for button event */ + struct mutex lock; + struct workqueue_struct *wq; + u8 hp_slot; }; struct event_info { u32 event_type; - u8 hp_slot; + struct slot *p_slot; + struct work_struct work; }; struct controller { - struct controller *next; - struct semaphore crit_sect; /* critical section semaphore */ - struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ + struct mutex crit_sect; /* critical section mutex */ + struct mutex cmd_lock; /* command lock */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; - struct pci_bus *pci_bus; - struct event_info event_queue[10]; - struct slot *slot; + struct list_head slot_list; struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ - u8 next_event; - u8 bus; - u8 device; - u8 function; u8 slot_device_offset; - u8 add_support; - enum pci_bus_speed speed; + u32 pcix_misc2_reg; /* for amd pogo errata */ u32 first_slot; /* First physical slot number */ - u8 slot_bus; /* Bus where the slots handled by this controller sit */ -}; - -struct hotplug_params { - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; + u32 cap_offset; + unsigned long mmio_base; + unsigned long mmio_size; + void __iomem *creg; + struct timer_list poll_timer; }; /* Define AMD SHPC ID */ -#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 +#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 +#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458 + +/* AMD PCI-X bridge registers */ +#define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C +#define PCIX_MISCII_OFFSET 0x48 +#define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80 + +/* AMD PCIX_MISCII masks and offsets */ +#define PERRNONFATALENABLE_MASK 0x00040000 +#define PERRFATALENABLE_MASK 0x00080000 +#define PERRFLOODENABLE_MASK 0x00100000 +#define SERRNONFATALENABLE_MASK 0x00200000 +#define SERRFATALENABLE_MASK 0x00400000 + +/* AMD PCIX_MISC_BRIDGE_ERRORS masks and offsets */ +#define PERR_OBSERVED_MASK 0x00000001 + +/* AMD PCIX_MEM_BASE_LIMIT masks */ +#define RSE_MASK 0x40000000 #define INT_BUTTON_IGNORE 0 #define INT_PRESENCE_ON 1 @@ -127,8 +157,6 @@ struct hotplug_params { #define POWERON_STATE 3 #define POWEROFF_STATE 4 -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - /* Error messages */ #define INTERLOCK_OPEN 0x00000002 #define ADD_NOT_SUPPORTED 0x00000003 @@ -140,46 +168,35 @@ struct hotplug_params { #define WRONG_BUS_FREQUENCY 0x0000000D #define POWER_FAILURE 0x0000000E -#define REMOVE_NOT_SUPPORTED 0x00000003 - -#define DISABLE_CARD 1 +int __must_check shpchp_create_ctrl_files(struct controller *ctrl); +void shpchp_remove_ctrl_files(struct controller *ctrl); +int shpchp_sysfs_enable_slot(struct slot *slot); +int shpchp_sysfs_disable_slot(struct slot *slot); +u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl); +u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl); +u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl); +u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); +int shpchp_configure_device(struct slot *p_slot); +int shpchp_unconfigure_device(struct slot *p_slot); +void cleanup_slots(struct controller *ctrl); +void shpchp_queue_pushbutton_work(struct work_struct *work); +int shpc_init(struct controller *ctrl, struct pci_dev *pdev); + +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} -/* - * 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" - -/* sysfs functions for the hotplug controller info */ -extern void shpchp_create_ctrl_files (struct controller *ctrl); - -/* controller functions */ -extern int shpchp_event_start_thread(void); -extern void shpchp_event_stop_thread(void); -extern int shpchp_enable_slot(struct slot *slot); -extern int shpchp_disable_slot(struct slot *slot); - -extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); - -/* pci functions */ -extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_configure_device(struct slot *p_slot); -extern int shpchp_unconfigure_device(struct slot *p_slot); -extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); -extern void get_hp_params_from_firmware(struct pci_dev *dev, - struct hotplug_params *hpp); -extern int shpchprm_get_physical_slot_number(struct controller *ctrl, - u32 *sun, u8 busnum, u8 devnum); -extern void shpchp_remove_ctrl_files(struct controller *ctrl); - - -/* Global variables */ -extern struct controller *shpchp_ctrl_list; +#ifdef CONFIG_ACPI +#include <linux/pci-acpi.h> +static inline int get_hp_hw_control_from_firmware(struct pci_dev *dev) +{ + u32 flags = OSC_PCI_SHPC_NATIVE_HP_CONTROL; + return acpi_get_hp_hw_control_from_firmware(dev, flags); +} +#else +#define get_hp_hw_control_from_firmware(dev) (0) +#endif struct ctrl_reg { volatile u32 base_offset; @@ -195,185 +212,137 @@ struct ctrl_reg { volatile u32 serr_loc; volatile u32 serr_intr_enable; volatile u32 slot1; - volatile u32 slot2; - volatile u32 slot3; - volatile u32 slot4; - volatile u32 slot5; - volatile u32 slot6; - volatile u32 slot7; - volatile u32 slot8; - volatile u32 slot9; - volatile u32 slot10; - volatile u32 slot11; - volatile u32 slot12; } __attribute__ ((packed)); /* offsets to the controller registers based on the above structure layout */ enum ctrl_offsets { - BASE_OFFSET = offsetof(struct ctrl_reg, base_offset), - SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1), - SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2), - SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config), - SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config), - MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl), - PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface), - CMD = offsetof(struct ctrl_reg, cmd), - CMD_STATUS = offsetof(struct ctrl_reg, cmd_status), - INTR_LOC = offsetof(struct ctrl_reg, intr_loc), - SERR_LOC = offsetof(struct ctrl_reg, serr_loc), - SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable), - SLOT1 = offsetof(struct ctrl_reg, slot1), - SLOT2 = offsetof(struct ctrl_reg, slot2), - SLOT3 = offsetof(struct ctrl_reg, slot3), - SLOT4 = offsetof(struct ctrl_reg, slot4), - SLOT5 = offsetof(struct ctrl_reg, slot5), - SLOT6 = offsetof(struct ctrl_reg, slot6), - SLOT7 = offsetof(struct ctrl_reg, slot7), - SLOT8 = offsetof(struct ctrl_reg, slot8), - SLOT9 = offsetof(struct ctrl_reg, slot9), - SLOT10 = offsetof(struct ctrl_reg, slot10), - SLOT11 = offsetof(struct ctrl_reg, slot11), - SLOT12 = offsetof(struct ctrl_reg, slot12), -}; -typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); -struct php_ctlr_state_s { - struct php_ctlr_state_s *pnext; - struct pci_dev *pci_dev; - unsigned int irq; - unsigned long flags; /* spinlock's */ - u32 slot_device_offset; - u32 num_slots; - struct timer_list int_poll_timer; /* Added for poll event */ - php_intr_callback_t attention_button_callback; - php_intr_callback_t switch_change_callback; - php_intr_callback_t presence_change_callback; - php_intr_callback_t power_fault_callback; - void *callback_instance_id; - void __iomem *creg; /* Ptr to controller register space */ + BASE_OFFSET = offsetof(struct ctrl_reg, base_offset), + SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1), + SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2), + SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config), + SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config), + MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl), + PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface), + CMD = offsetof(struct ctrl_reg, cmd), + CMD_STATUS = offsetof(struct ctrl_reg, cmd_status), + INTR_LOC = offsetof(struct ctrl_reg, intr_loc), + SERR_LOC = offsetof(struct ctrl_reg, serr_loc), + SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable), + SLOT1 = offsetof(struct ctrl_reg, slot1), }; -/* Inline functions */ - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) +static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot) { - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; + return hotplug_slot->private; } -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ +static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device) +{ struct slot *slot; - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; + list_for_each_entry(slot, &ctrl->slot_list, slot_list) { + if (slot->device == device) + return slot; } - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; + ctrl_err(ctrl, "Slot (device=0x%02x) not found\n", device); + return NULL; } -static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device) +static inline void amd_pogo_errata_save_misc_reg(struct slot *p_slot) { - struct slot *p_slot, *tmp_slot = NULL; - - if (!ctrl) - return NULL; + u32 pcix_misc2_temp; - p_slot = ctrl->slot; + /* save MiscII register */ + pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp); - while (p_slot && (p_slot->device != device)) { - tmp_slot = p_slot; - p_slot = p_slot->next; - } - if (p_slot == NULL) { - err("ERROR: shpchp_find_slot device=0x%x\n", device); - p_slot = tmp_slot; - } + p_slot->ctrl->pcix_misc2_reg = pcix_misc2_temp; - return (p_slot); + /* clear SERR/PERR enable bits */ + pcix_misc2_temp &= ~SERRFATALENABLE_MASK; + pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK; + pcix_misc2_temp &= ~PERRFLOODENABLE_MASK; + pcix_misc2_temp &= ~PERRFATALENABLE_MASK; + pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK; + pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp); } -static inline int wait_for_ctrl_irq (struct controller *ctrl) +static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot) { - DECLARE_WAITQUEUE(wait, current); - int retval = 0; - - add_wait_queue(&ctrl->queue, &wait); - - if (!shpchp_poll_mode) { - /* Sleep for up to 1 second */ - msleep_interruptible(1000); - } else { - /* Sleep for up to 2 seconds */ - msleep_interruptible(2000); + u32 pcix_misc2_temp; + u32 pcix_bridge_errors_reg; + u32 pcix_mem_base_reg; + u8 perr_set; + u8 rse_set; + + /* write-one-to-clear Bridge_Errors[ PERR_OBSERVED ] */ + pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, &pcix_bridge_errors_reg); + perr_set = pcix_bridge_errors_reg & PERR_OBSERVED_MASK; + if (perr_set) { + ctrl_dbg(p_slot->ctrl, + "Bridge_Errors[ PERR_OBSERVED = %08X] (W1C)\n", + perr_set); + + pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, perr_set); } - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; - - return retval; -} -#define SLOT_NAME_SIZE 10 + /* write-one-to-clear Memory_Base_Limit[ RSE ] */ + pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, &pcix_mem_base_reg); + rse_set = pcix_mem_base_reg & RSE_MASK; + if (rse_set) { + ctrl_dbg(p_slot->ctrl, "Memory_Base_Limit[ RSE ] (W1C)\n"); -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number); + pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, rse_set); + } + /* restore MiscII register */ + pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp ); + + if (p_slot->ctrl->pcix_misc2_reg & SERRFATALENABLE_MASK) + pcix_misc2_temp |= SERRFATALENABLE_MASK; + else + pcix_misc2_temp &= ~SERRFATALENABLE_MASK; + + if (p_slot->ctrl->pcix_misc2_reg & SERRNONFATALENABLE_MASK) + pcix_misc2_temp |= SERRNONFATALENABLE_MASK; + else + pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK; + + if (p_slot->ctrl->pcix_misc2_reg & PERRFLOODENABLE_MASK) + pcix_misc2_temp |= PERRFLOODENABLE_MASK; + else + pcix_misc2_temp &= ~PERRFLOODENABLE_MASK; + + if (p_slot->ctrl->pcix_misc2_reg & PERRFATALENABLE_MASK) + pcix_misc2_temp |= PERRFATALENABLE_MASK; + else + pcix_misc2_temp &= ~PERRFATALENABLE_MASK; + + if (p_slot->ctrl->pcix_misc2_reg & PERRNONFATALENABLE_MASK) + pcix_misc2_temp |= PERRNONFATALENABLE_MASK; + else + pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK; + pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp); } -enum php_ctlr_type { - PCI, - ISA, - ACPI -}; - -int shpc_init( struct controller *ctrl, struct pci_dev *pdev); - -int shpc_get_ctlr_slot_config( struct controller *ctrl, - int *num_ctlr_slots, - int *first_device_num, - int *physical_slot_num, - int *updown, - int *flags); - struct hpc_ops { - int (*power_on_slot ) (struct slot *slot); - int (*slot_enable ) (struct slot *slot); - int (*slot_disable ) (struct slot *slot); - int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed); - int (*get_power_status) (struct slot *slot, u8 *status); - int (*get_attention_status) (struct slot *slot, u8 *status); - int (*set_attention_status) (struct slot *slot, u8 status); - int (*get_latch_status) (struct slot *slot, u8 *status); - int (*get_adapter_status) (struct slot *slot, u8 *status); - - int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_adapter_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_mode1_ECC_cap) (struct slot *slot, u8 *mode); - int (*get_prog_int) (struct slot *slot, u8 *prog_int); - - int (*query_power_fault) (struct slot *slot); - void (*green_led_on) (struct slot *slot); - void (*green_led_off) (struct slot *slot); - void (*green_led_blink) (struct slot *slot); - void (*release_ctlr) (struct controller *ctrl); - int (*check_cmd_status) (struct controller *ctrl); + int (*power_on_slot)(struct slot *slot); + int (*slot_enable)(struct slot *slot); + int (*slot_disable)(struct slot *slot); + int (*set_bus_speed_mode)(struct slot *slot, enum pci_bus_speed speed); + int (*get_power_status)(struct slot *slot, u8 *status); + int (*get_attention_status)(struct slot *slot, u8 *status); + int (*set_attention_status)(struct slot *slot, u8 status); + int (*get_latch_status)(struct slot *slot, u8 *status); + int (*get_adapter_status)(struct slot *slot, u8 *status); + int (*get_adapter_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_mode1_ECC_cap)(struct slot *slot, u8 *mode); + int (*get_prog_int)(struct slot *slot, u8 *prog_int); + int (*query_power_fault)(struct slot *slot); + void (*green_led_on)(struct slot *slot); + void (*green_led_off)(struct slot *slot); + void (*green_led_blink)(struct slot *slot); + void (*release_ctlr)(struct controller *ctrl); + int (*check_cmd_status)(struct controller *ctrl); }; #endif /* _SHPCHP_H */ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 63628e01dd4..294ef4b10cf 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -31,14 +31,14 @@ #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> +#include <linux/slab.h> #include <linux/pci.h> #include "shpchp.h" /* Global variables */ -int shpchp_debug; -int shpchp_poll_mode; +bool shpchp_debug; +bool shpchp_poll_mode; int shpchp_poll_time; -struct controller *shpchp_ctrl_list; /* = NULL */ #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" @@ -57,7 +57,6 @@ MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); #define SHPC_MODULE_NAME "shpchp" -static int shpc_start_thread (void); static int set_attention_status (struct hotplug_slot *slot, u8 value); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); @@ -65,11 +64,8 @@ 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_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); static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, @@ -77,8 +73,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, }; /** @@ -89,148 +83,123 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } static int init_slots(struct controller *ctrl) { - struct slot *new_slot; - u8 number_of_slots; - u8 slot_device; - u32 slot_number, sun; - int result = -ENOMEM; - - number_of_slots = ctrl->num_slots; - slot_device = ctrl->slot_device_offset; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!new_slot) + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char name[SLOT_NAME_SIZE]; + int retval; + int i; + + for (i = 0; i < ctrl->num_slots; i++) { + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + retval = -ENOMEM; goto error; + } - memset(new_slot, 0, sizeof(struct slot)); - new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!new_slot->hotplug_slot) + hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) { + retval = -ENOMEM; goto error_slot; - memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + } + slot->hotplug_slot = hotplug_slot; - new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!new_slot->hotplug_slot->info) + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + retval = -ENOMEM; goto error_hpslot; - memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); - new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); - if (!new_slot->hotplug_slot->name) + } + hotplug_slot->info = info; + + slot->hp_slot = i; + slot->ctrl = ctrl; + slot->bus = ctrl->pci_dev->subordinate->number; + slot->device = ctrl->slot_device_offset + i; + slot->hpc_ops = ctrl->hpc_ops; + slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); + + slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); + if (!slot->wq) { + retval = -ENOMEM; goto error_info; + } - new_slot->magic = SLOT_MAGIC; - new_slot->ctrl = ctrl; - new_slot->bus = ctrl->slot_bus; - new_slot->device = slot_device; - new_slot->hpc_ops = ctrl->hpc_ops; - - if (shpchprm_get_physical_slot_number(ctrl, &sun, - new_slot->bus, new_slot->device)) - goto error_name; - - new_slot->number = sun; - new_slot->hp_slot = slot_device - ctrl->slot_device_offset; + mutex_init(&slot->lock); + INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); /* register this slot with the hotplug pci core */ - new_slot->hotplug_slot->private = new_slot; - new_slot->hotplug_slot->release = &release_slot; - make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); - new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops; - - new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); - new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status)); - new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status)); - new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status)); - - dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus, - new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset); - result = pci_hp_register (new_slot->hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - goto error_name; + hotplug_slot->private = slot; + hotplug_slot->release = &release_slot; + snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); + hotplug_slot->ops = &shpchp_hotplug_slot_ops; + + ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x hp_slot=%x sun=%x slot_device_offset=%x\n", + pci_domain_nr(ctrl->pci_dev->subordinate), + slot->bus, slot->device, slot->hp_slot, slot->number, + ctrl->slot_device_offset); + retval = pci_hp_register(slot->hotplug_slot, + ctrl->pci_dev->subordinate, slot->device, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_register failed with error %d\n", + retval); + goto error_slotwq; } - new_slot->next = ctrl->slot; - ctrl->slot = new_slot; + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); - number_of_slots--; - slot_device++; - slot_number += ctrl->slot_num_inc; + list_add(&slot->slot_list, &ctrl->slot_list); } return 0; - -error_name: - kfree(new_slot->hotplug_slot->name); +error_slotwq: + destroy_workqueue(slot->wq); error_info: - kfree(new_slot->hotplug_slot->info); + kfree(info); error_hpslot: - kfree(new_slot->hotplug_slot); + kfree(hotplug_slot); error_slot: - kfree(new_slot); + kfree(slot); error: - return result; -} - -static void cleanup_slots(struct controller *ctrl) -{ - struct slot *old_slot, *next_slot; - - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister(old_slot->hotplug_slot); - old_slot = next_slot; - } + return retval; } -static int get_ctlr_slot_config(struct controller *ctrl) +void cleanup_slots(struct controller *ctrl) { - int num_ctlr_slots; - int first_device_num; - int physical_slot_num; - int updown; - int rc; - int flags; - - rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags); - if (rc) { - err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); - return -1; + struct list_head *tmp; + struct list_head *next; + struct slot *slot; + + list_for_each_safe(tmp, next, &ctrl->slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + cancel_delayed_work(&slot->work); + destroy_workqueue(slot->wq); + pci_hp_deregister(slot->hotplug_slot); } - - ctrl->num_slots = num_ctlr_slots; - ctrl->slot_device_offset = first_device_num; - ctrl->first_slot = physical_slot_num; - ctrl->slot_num_inc = updown; /* either -1 or 1 */ - - dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n", - __FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, ctrl->bus, ctrl->device); - - return 0; } - /* * set_attention_status - Turns the Amber LED for a slot on, off or blink */ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); hotplug_slot->info->attention_status = status; slot->hpc_ops->set_attention_status(slot, status); @@ -238,32 +207,33 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) return 0; } - static int enable_slot (struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); - return shpchp_enable_slot(slot); + return shpchp_sysfs_enable_slot(slot); } - static int disable_slot (struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); - return shpchp_disable_slot(slot); + return shpchp_sysfs_disable_slot(slot); } static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) @@ -274,10 +244,11 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) @@ -288,10 +259,11 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) @@ -302,10 +274,11 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", + __func__, slot_name(slot)); retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) @@ -314,141 +287,57 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) return 0; } -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_max_bus_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - retval = slot->hpc_ops->get_cur_bus_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - static int is_shpc_capable(struct pci_dev *dev) { - if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) - return 1; - if (pci_find_capability(dev, PCI_CAP_ID_SHPC)) - return 1; - - return 0; + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) + return 1; + if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) + return 0; + if (get_hp_hw_control_from_firmware(dev)) + return 0; + return 1; } static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; struct controller *ctrl; - struct slot *t_slot; - int first_device_num; /* first PCI device number supported by this SHPC */ - int num_ctlr_slots; /* number of slots supported by this SHPC */ if (!is_shpc_capable(pdev)) return -ENODEV; - ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { - err("%s : out of memory\n", __FUNCTION__); + dev_err(&pdev->dev, "%s: Out of memory\n", __func__); goto err_out_none; } - memset(ctrl, 0, sizeof(struct controller)); + INIT_LIST_HEAD(&ctrl->slot_list); rc = shpc_init(ctrl, pdev); if (rc) { - dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME); + ctrl_dbg(ctrl, "Controller initialization failed\n"); goto err_out_free_ctrl; } - ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ - pci_set_drvdata(pdev, ctrl); - ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("out of memory\n"); - rc = -ENOMEM; - goto err_out_unmap_mmio_region; - } - - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); - ctrl->bus = pdev->bus->number; - ctrl->slot_bus = pdev->subordinate->number; - - ctrl->device = PCI_SLOT(pdev->devfn); - ctrl->function = PCI_FUNC(pdev->devfn); - dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, ctrl->function, pdev->irq); - - /* - * Save configuration headers for this and subordinate PCI buses - */ - - rc = get_ctlr_slot_config(ctrl); - if (rc) { - err(msg_initialization_err, rc); - goto err_out_free_ctrl_bus; - } - first_device_num = ctrl->slot_device_offset; - num_ctlr_slots = ctrl->num_slots; - - ctrl->add_support = 1; - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { - err(msg_initialization_err, 6); - goto err_out_free_ctrl_slot; - } - - /* Now hpc_functions (slot->hpc_ops->functions) are ready */ - t_slot = shpchp_find_slot(ctrl, first_device_num); - - /* Check for operation bus speed */ - rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed); - dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot); - - if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) { - err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n"); - ctrl->speed = PCI_SPEED_33MHz; - } - - /* Finish setting up the hot plug ctrl device */ - ctrl->next_event = 0; - - if (!shpchp_ctrl_list) { - shpchp_ctrl_list = ctrl; - ctrl->next = NULL; - } else { - ctrl->next = shpchp_ctrl_list; - shpchp_ctrl_list = ctrl; + ctrl_err(ctrl, "Slot initialization failed\n"); + goto err_out_release_ctlr; } - shpchp_create_ctrl_files(ctrl); + rc = shpchp_create_ctrl_files(ctrl); + if (rc) + goto err_cleanup_slots; return 0; -err_out_free_ctrl_slot: +err_cleanup_slots: cleanup_slots(ctrl); -err_out_free_ctrl_bus: - kfree(ctrl->pci_bus); -err_out_unmap_mmio_region: +err_out_release_ctlr: ctrl->hpc_ops->release_ctlr(ctrl); err_out_free_ctrl: kfree(ctrl); @@ -456,104 +345,43 @@ err_out_none: return -ENODEV; } - -static int shpc_start_thread(void) -{ - int retval = 0; - - dbg("Initialize + Start the notification/polling mechanism \n"); - - retval = shpchp_event_start_thread(); - if (retval) { - dbg("shpchp_event_start_thread() failed\n"); - return retval; - } - - return retval; -} - -static void __exit unload_shpchpd(void) +static void shpc_remove(struct pci_dev *dev) { - struct controller *ctrl; - struct controller *tctrl; - - ctrl = shpchp_ctrl_list; - - while (ctrl) { - shpchp_remove_ctrl_files(ctrl); - cleanup_slots(ctrl); - - kfree (ctrl->pci_bus); - ctrl->hpc_ops->release_ctlr(ctrl); - - tctrl = ctrl; - ctrl = ctrl->next; - - kfree(tctrl); - } - - /* Stop the notification mechanism */ - shpchp_event_stop_thread(); + struct controller *ctrl = pci_get_drvdata(dev); + shpchp_remove_ctrl_files(ctrl); + ctrl->hpc_ops->release_ctlr(ctrl); + kfree(ctrl); } - static struct pci_device_id shpcd_pci_tbl[] = { - { - .class = ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), - .class_mask = ~0, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - + {PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0)}, { /* end: all zeroes */ } }; - MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl); - - static struct pci_driver shpc_driver = { .name = SHPC_MODULE_NAME, .id_table = shpcd_pci_tbl, .probe = shpc_probe, - /* remove: shpc_remove_one, */ + .remove = shpc_remove, }; - - static int __init shpcd_init(void) { - int retval = 0; - -#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - shpchp_poll_mode = 1; -#endif - - retval = shpc_start_thread(); - if (retval) - goto error_hpc_init; + int retval; retval = pci_register_driver(&shpc_driver); - dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); + dbg("%s: pci_register_driver = %d\n", __func__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); -error_hpc_init: - if (retval) { - shpchp_event_stop_thread(); - } return retval; } static void __exit shpcd_cleanup(void) { dbg("unload_shpchpd()\n"); - unload_shpchpd(); - pci_unregister_driver(&shpc_driver); - info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 58619359ad0..a81fb67ea9a 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -30,143 +30,104 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/smp_lock.h> +#include <linux/slab.h> #include <linux/pci.h> #include "../pci.h" #include "shpchp.h" -static void interrupt_event_handler(struct controller *ctrl); +static void interrupt_event_handler(struct work_struct *work); +static int shpchp_enable_slot(struct slot *p_slot); +static int shpchp_disable_slot(struct slot *p_slot); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ +static int queue_interrupt_event(struct slot *p_slot, u32 event_type) +{ + struct event_info *info; + + info = kmalloc(sizeof(*info), GFP_ATOMIC); + if (!info) + return -ENOMEM; + + info->event_type = event_type; + info->p_slot = p_slot; + INIT_WORK(&info->work, interrupt_event_handler); + + queue_work(p_slot->wq, &info->work); -u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) + return 0; +} + +u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; - u8 rc = 0; - u8 getstatus; - struct event_info *taskInfo; + u32 event_type; /* Attention Button Change */ - dbg("shpchp: Attention button interrupt received.\n"); - - /* This is the structure that tells the worker thread what to do */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + ctrl_dbg(ctrl, "Attention button interrupt received\n"); + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); - p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_BUTTON_PRESS; - - if ((p_slot->state == BLINKINGON_STATE) - || (p_slot->state == BLINKINGOFF_STATE)) { - /* Cancel if we are still blinking; this means that we press the - * attention again before the 5 sec. limit expires to cancel hot-add - * or hot-remove - */ - taskInfo->event_type = INT_BUTTON_CANCEL; - info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); - } else if ((p_slot->state == POWERON_STATE) - || (p_slot->state == POWEROFF_STATE)) { - /* Ignore if the slot is on power-on or power-off state; this - * means that the previous attention button action to hot-add or - * hot-remove is undergoing - */ - taskInfo->event_type = INT_BUTTON_IGNORE; - info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); - } + ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_BUTTON_PRESS; - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); return 0; } -u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) +u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; - u8 rc = 0; u8 getstatus; - struct event_info *taskInfo; + u32 event_type; /* Switch Change */ - dbg("shpchp: Switch interrupt received.\n"); - - /* This is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; + ctrl_dbg(ctrl, "Switch interrupt received\n"); - rc++; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - dbg("%s: Card present %x Power status %x\n", __FUNCTION__, - p_slot->presence_save, p_slot->pwr_save); + ctrl_dbg(ctrl, "Card present %x Power status %x\n", + p_slot->presence_save, p_slot->pwr_save); if (getstatus) { /* * Switch opened */ - info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_SWITCH_OPEN; + ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_SWITCH_OPEN; if (p_slot->pwr_save && p_slot->presence_save) { - taskInfo->event_type = INT_POWER_FAULT; - err("Surprise Removal of card\n"); + event_type = INT_POWER_FAULT; + ctrl_err(ctrl, "Surprise Removal of card\n"); } } else { /* * Switch closed */ - info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_SWITCH_CLOSE; + ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_SWITCH_CLOSE; } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); - return rc; + return 1; } -u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) +u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; - u8 rc = 0; - /*u8 temp_byte;*/ - struct event_info *taskInfo; + u32 event_type; /* Presence Change */ - dbg("shpchp: Presence/Notify input change.\n"); + ctrl_dbg(ctrl, "Presence/Notify input change\n"); - /* This is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - /* + /* * Save the presence state */ p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); @@ -174,352 +135,188 @@ 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); - taskInfo->event_type = INT_PRESENCE_ON; + ctrl_info(ctrl, "Card present on Slot(%s)\n", + slot_name(p_slot)); + event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_PRESENCE_OFF; + ctrl_info(ctrl, "Card not present on Slot(%s)\n", + slot_name(p_slot)); + event_type = INT_PRESENCE_OFF; } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ + queue_interrupt_event(p_slot, event_type); - return rc; + return 1; } -u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) +u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; - u8 rc = 0; - struct event_info *taskInfo; + u32 event_type; /* Power fault */ - dbg("shpchp: Power fault interrupt received.\n"); + ctrl_dbg(ctrl, "Power fault interrupt received\n"); - /* This is the structure that tells the worker thread - * what to do - */ - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { + if (!(p_slot->hpc_ops->query_power_fault(p_slot))) { /* * Power fault Cleared */ - info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n", + slot_name(p_slot)); p_slot->status = 0x00; - taskInfo->event_type = INT_POWER_FAULT_CLEAR; + event_type = INT_POWER_FAULT_CLEAR; } else { /* * Power fault */ - info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); - taskInfo->event_type = INT_POWER_FAULT; + ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot)); + event_type = INT_POWER_FAULT; /* set power fault status for this board */ p_slot->status = 0xFF; - info("power fault bit %x set\n", hp_slot); + ctrl_info(ctrl, "Power fault bit %x set\n", hp_slot); } - if (rc) - up(&event_semaphore); /* signal event thread that new event is posted */ - return rc; + queue_interrupt_event(p_slot, event_type); + + return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) -{ +{ int rc = 0; - dbg("%s: change to speed %d\n", __FUNCTION__, speed); - down(&ctrl->crit_sect); + ctrl_dbg(ctrl, "Change speed to %d\n", speed); if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { - err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); + ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", + __func__); return WRONG_BUS_FREQUENCY; } - wait_for_ctrl_irq (ctrl); - - if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { - err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", - __FUNCTION__); - err("%s: Error code (%d)\n", __FUNCTION__, rc); - up(&ctrl->crit_sect); - return WRONG_BUS_FREQUENCY; - } - up(&ctrl->crit_sect); return rc; } static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) -{ +{ int rc = 0; - - if (flag != 0) { /* Other slots on the same bus are occupied */ - if ( asp < bsp ) { - err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp); - return WRONG_BUS_FREQUENCY; + + /* + * If other slots on the same bus are occupied, we cannot + * change the bus speed. + */ + if (flag) { + if (asp < bsp) { + ctrl_err(ctrl, "Speed of bus %x and adapter %x mismatch\n", + bsp, asp); + rc = WRONG_BUS_FREQUENCY; } + return rc; + } + + if (asp < msp) { + if (bsp != asp) + rc = change_bus_speed(ctrl, pslot, asp); } else { - /* Other slots on the same bus are empty */ - if (msp == bsp) { - /* if adapter_speed >= bus_speed, do nothing */ - if (asp < bsp) { - /* - * Try to lower bus speed to accommodate the adapter if other slots - * on the same controller are empty - */ - if ((rc = change_bus_speed(ctrl, pslot, asp))) - return rc; - } - } else { - if (asp < msp) { - if ((rc = change_bus_speed(ctrl, pslot, asp))) - return rc; - } else { - if ((rc = change_bus_speed(ctrl, pslot, msp))) - return rc; - } - } + if (bsp != msp) + rc = change_bus_speed(ctrl, pslot, msp); } return rc; } /** * board_added - Called after a board has been added to the system. + * @p_slot: target &slot * - * Turns power on for the board - * Configures board - * + * Turns power on for the board. + * Configures board. */ static int board_added(struct slot *p_slot) { u8 hp_slot; u8 slots_not_empty = 0; int rc = 0; - enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; - u8 pi, mode; + enum pci_bus_speed asp, bsp, msp; struct controller *ctrl = p_slot->ctrl; + struct pci_bus *parent = ctrl->pci_dev->subordinate; hp_slot = p_slot->device - ctrl->slot_device_offset; - dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", - __FUNCTION__, p_slot->device, - ctrl->slot_device_offset, hp_slot); - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); + ctrl_dbg(ctrl, "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", + __func__, p_slot->device, ctrl->slot_device_offset, hp_slot); /* Power on slot without connecting to bus */ rc = p_slot->hpc_ops->power_on_slot(p_slot); if (rc) { - err("%s: Failed to power on slot\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return -1; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + ctrl_err(ctrl, "Failed to power on slot\n"); return -1; } - if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { - if (slots_not_empty) - return WRONG_BUS_FREQUENCY; - if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { - err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return WRONG_BUS_FREQUENCY; - } - wait_for_ctrl_irq (ctrl); - - if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { - err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", - __FUNCTION__); - err("%s: Error code (%d)\n", __FUNCTION__, rc); - up(&ctrl->crit_sect); + ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", + __func__); return WRONG_BUS_FREQUENCY; } + /* turn on board, blink green LED, turn off Amber LED */ if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { - err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); + ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); return rc; } - wait_for_ctrl_irq (ctrl); - - if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { - err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); - up(&ctrl->crit_sect); - return rc; - } - } - - rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed); - /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */ - /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */ - /* 0xd = PCI-X 133 Mhz 533 */ - /* This encoding is different from the one used in cur_bus_speed & */ - /* max_bus_speed */ - - if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { - err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return WRONG_BUS_FREQUENCY; } - rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); - if (rc || bus_speed == PCI_SPEED_UNKNOWN) { - err("%s: Can't get bus operation speed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); + if (rc) { + ctrl_err(ctrl, "Can't get adapter speed or bus mode mismatch\n"); return WRONG_BUS_FREQUENCY; } - rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed); - if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) { - err("%s: Can't get max bus operation speed\n", __FUNCTION__); - max_bus_speed = bus_speed; - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { - err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); - pi = 1; - } + bsp = ctrl->pci_dev->subordinate->cur_bus_speed; + msp = ctrl->pci_dev->subordinate->max_bus_speed; /* Check if there are other slots or devices on the same bus */ if (!list_empty(&ctrl->pci_dev->subordinate->devices)) slots_not_empty = 1; - dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__, - slots_not_empty, pi); - dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n", - adapter_speed, bus_speed, max_bus_speed); + ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, max_bus_speed %d\n", + __func__, slots_not_empty, asp, + bsp, msp); - if (pi == 2) { - dbg("%s: In PI = %d\n", __FUNCTION__, pi); - if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) { - err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__); - mode = 0; - } - - switch (adapter_speed) { - case PCI_SPEED_133MHz_PCIX_533: - case PCI_SPEED_133MHz_PCIX_266: - if ((bus_speed != adapter_speed) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - break; - case PCI_SPEED_133MHz_PCIX_ECC: - case PCI_SPEED_133MHz_PCIX: - if (mode) { /* Bus - Mode 1 ECC */ - if ((bus_speed != 0x7) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - } else { - if ((bus_speed != 0x4) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - } - break; - case PCI_SPEED_66MHz_PCIX_ECC: - case PCI_SPEED_66MHz_PCIX: - if (mode) { /* Bus - Mode 1 ECC */ - if ((bus_speed != 0x5) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - } else { - if ((bus_speed != 0x2) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - } - break; - case PCI_SPEED_66MHz: - if ((bus_speed != 0x1) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - break; - case PCI_SPEED_33MHz: - if (bus_speed > 0x0) { - if (slots_not_empty == 0) { - if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed))) - return rc; - } else { - err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); - return WRONG_BUS_FREQUENCY; - } - } - break; - default: - err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); - return WRONG_BUS_FREQUENCY; - } - } else { - /* If adpater_speed == bus_speed, nothing to do here */ - dbg("%s: In PI = %d\n", __FUNCTION__, pi); - if ((adapter_speed != bus_speed) && - ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) - return rc; - } + rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); + if (rc) + return rc; - down(&ctrl->crit_sect); /* turn on board, blink green LED, turn off Amber LED */ if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { - err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); + ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); return rc; } - wait_for_ctrl_irq (ctrl); - - if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { - err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); - up(&ctrl->crit_sect); - return rc; - } - - up(&ctrl->crit_sect); /* Wait for ~1 second */ - wait_for_ctrl_irq (ctrl); + msleep(1000); - dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); + ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status); /* Check for a power fault */ if (p_slot->status == 0xFF) { /* power fault occurred, but it was benign */ - dbg("%s: power fault\n", __FUNCTION__); + ctrl_dbg(ctrl, "%s: Power fault\n", __func__); rc = POWER_FAILURE; p_slot->status = 0; goto err_exit; } if (shpchp_configure_device(p_slot)) { - err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, - p_slot->device); + ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n", + pci_domain_nr(parent), p_slot->bus, p_slot->device); goto err_exit; } @@ -527,52 +324,26 @@ static int board_added(struct slot *p_slot) p_slot->is_a_board = 0x01; p_slot->pwr_save = 1; - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return 0; err_exit: - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - /* turn off slot, turn on Amber LED, turn off Green LED */ rc = p_slot->hpc_ops->slot_disable(p_slot); if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", + __func__); return rc; } - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return(rc); } /** - * remove_board - Turns off slot and LED's - * + * remove_board - Turns off slot and LEDs + * @p_slot: target &slot */ static int remove_board(struct slot *p_slot) { @@ -586,46 +357,25 @@ static int remove_board(struct slot *p_slot) hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot); /* Change status to shutdown */ if (p_slot->is_a_board) p_slot->status = 0x01; - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - /* turn off slot, turn on Amber LED, turn off Green LED */ rc = p_slot->hpc_ops->slot_disable(p_slot); if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", + __func__); return rc; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); if (rc) { - err("%s: Issue of Set Attention command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + ctrl_err(ctrl, "Issue of Set Attention command failed\n"); return rc; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); p_slot->pwr_save = 0; p_slot->is_a_board = 0; @@ -634,114 +384,78 @@ static int remove_board(struct slot *p_slot) } -static void pushbutton_helper_thread (unsigned long data) -{ - pushbutton_pending = data; - - up(&event_semaphore); -} - +struct pushbutton_work_info { + struct slot *p_slot; + struct work_struct work; +}; /** - * shpchp_pushbutton_thread + * shpchp_pushbutton_thread - handle pushbutton events + * @work: &struct work_struct to be handled * - * Scheduled procedure to handle blocking stuff for the pushbuttons + * Scheduled procedure to handle blocking stuff for the pushbuttons. * Handles all pending events and exits. - * */ -static void shpchp_pushbutton_thread (unsigned long slot) +static void shpchp_pushbutton_thread(struct work_struct *work) { - struct slot *p_slot = (struct slot *) slot; - u8 getstatus; - - pushbutton_pending = 0; - - if (!p_slot) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); - return; - } - - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { - p_slot->state = POWEROFF_STATE; - + struct pushbutton_work_info *info = + container_of(work, struct pushbutton_work_info, work); + struct slot *p_slot = info->p_slot; + + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case POWEROFF_STATE: + mutex_unlock(&p_slot->lock); shpchp_disable_slot(p_slot); + mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; - } else { - p_slot->state = POWERON_STATE; - - if (shpchp_enable_slot(p_slot)) { - /* Wait for exclusive access to hardware */ - down(&p_slot->ctrl->crit_sect); - + break; + case POWERON_STATE: + mutex_unlock(&p_slot->lock); + if (shpchp_enable_slot(p_slot)) p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - up(&p_slot->ctrl->crit_sect); - } + mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; + break; + default: + break; } + mutex_unlock(&p_slot->lock); - return; + kfree(info); } - -/* this is the main worker thread */ -static int event_thread(void* data) +void shpchp_queue_pushbutton_work(struct work_struct *work) { - struct controller *ctrl; - lock_kernel(); - daemonize("shpchpd_event"); - unlock_kernel(); - - while (1) { - dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished || signal_pending(current)) - break; - /* Do stuff here */ - if (pushbutton_pending) - shpchp_pushbutton_thread(pushbutton_pending); - else - for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next) - interrupt_event_handler(ctrl); - } - dbg("event_thread signals exit\n"); - up(&event_exit); - return 0; -} + struct slot *p_slot = container_of(work, struct slot, work.work); + struct pushbutton_work_info *info; -int shpchp_event_start_thread (void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - init_MUTEX_LOCKED(&event_semaphore); - pid = kernel_thread(event_thread, NULL, 0); - - if (pid < 0) { - err ("Can't start up our event thread\n"); - return -1; + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); + return; } - return 0; -} + info->p_slot = p_slot; + INIT_WORK(&info->work, shpchp_pushbutton_thread); - -void shpchp_event_stop_thread (void) -{ - event_finished = 1; - up(&event_semaphore); - down(&event_exit); + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGOFF_STATE: + p_slot->state = POWEROFF_STATE; + break; + case BLINKINGON_STATE: + p_slot->state = POWERON_STATE; + break; + default: + kfree(info); + goto out; + } + queue_work(p_slot->wq, &info->work); + out: + mutex_unlock(&p_slot->lock); } - static int update_slot_info (struct slot *slot) { struct hotplug_slot_info *info; @@ -761,221 +475,252 @@ static int update_slot_info (struct slot *slot) return result; } -static void interrupt_event_handler(struct controller *ctrl) +/* + * Note: This function must be called with slot->lock held + */ +static void handle_button_press_event(struct slot *p_slot) { - int loop = 0; - int change = 1; - u8 hp_slot; u8 getstatus; - struct slot *p_slot; + struct controller *ctrl = p_slot->ctrl; - while (change) { - change = 0; - - for (loop = 0; loop < 10; loop++) { - if (ctrl->event_queue[loop].event_type != 0) { - dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, - ctrl->event_queue[loop].event_type); - hp_slot = ctrl->event_queue[loop].hp_slot; - - p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { - dbg("%s: button cancel\n", __FUNCTION__); - del_timer(&p_slot->task_event); - - switch (p_slot->state) { - case BLINKINGOFF_STATE: - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - break; - case BLINKINGON_STATE: - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - break; - default: - warn("Not a valid state\n"); - return; - } - info(msg_button_cancel, p_slot->number); - p_slot->state = STATIC_STATE; - } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { - /* Button Pressed (No action on 1st press...) */ - dbg("%s: Button pressed\n", __FUNCTION__); - - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { - /* slot is on */ - dbg("%s: slot is on\n", __FUNCTION__); - p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); - } else { - /* slot is off */ - dbg("%s: slot is off\n", __FUNCTION__); - p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); - } - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* blink green LED and turn off amber */ - p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - - init_timer(&p_slot->task_event); - p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ - p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; - p_slot->task_event.data = (unsigned long) p_slot; - - dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot); - add_timer(&p_slot->task_event); - } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { - /***********POWER FAULT********************/ - dbg("%s: power fault\n", __FUNCTION__); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->set_attention_status(p_slot, 1); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - } else { - /* refresh notification */ - if (p_slot) - update_slot_info(p_slot); - } - - ctrl->event_queue[loop].event_type = 0; - - change = 1; - } - } /* End of FOR loop */ + switch (p_slot->state) { + case STATIC_STATE: + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = BLINKINGOFF_STATE; + ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", + slot_name(p_slot)); + } else { + p_slot->state = BLINKINGON_STATE; + ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", + slot_name(p_slot)); + } + /* blink green LED and turn off amber */ + p_slot->hpc_ops->green_led_blink(p_slot); + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); + break; + case BLINKINGOFF_STATE: + case BLINKINGON_STATE: + /* + * Cancel if we are still blinking; this means that we + * press the attention again before the 5 sec. limit + * expires to cancel hot-add or hot-remove + */ + ctrl_info(ctrl, "Button cancel on Slot(%s)\n", + slot_name(p_slot)); + cancel_delayed_work(&p_slot->work); + if (p_slot->state == BLINKINGOFF_STATE) + p_slot->hpc_ops->green_led_on(p_slot); + else + p_slot->hpc_ops->green_led_off(p_slot); + p_slot->hpc_ops->set_attention_status(p_slot, 0); + ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", + slot_name(p_slot)); + p_slot->state = STATIC_STATE; + break; + case POWEROFF_STATE: + case POWERON_STATE: + /* + * Ignore if the slot is on power-on or power-off state; + * this means that the previous attention button action + * to hot-add or hot-remove is undergoing + */ + ctrl_info(ctrl, "Button ignore on Slot(%s)\n", + slot_name(p_slot)); + update_slot_info(p_slot); + break; + default: + ctrl_warn(ctrl, "Not a valid state\n"); + break; } +} - return; +static void interrupt_event_handler(struct work_struct *work) +{ + struct event_info *info = container_of(work, struct event_info, work); + struct slot *p_slot = info->p_slot; + + mutex_lock(&p_slot->lock); + switch (info->event_type) { + case INT_BUTTON_PRESS: + handle_button_press_event(p_slot); + break; + case INT_POWER_FAULT: + ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__); + p_slot->hpc_ops->set_attention_status(p_slot, 1); + p_slot->hpc_ops->green_led_off(p_slot); + break; + default: + update_slot_info(p_slot); + break; + } + mutex_unlock(&p_slot->lock); + + kfree(info); } -int shpchp_enable_slot (struct slot *p_slot) +static int shpchp_enable_slot (struct slot *p_slot) { u8 getstatus = 0; - int rc; + int rc, retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; /* Check to see if (latch closed, card present, power off) */ - down(&p_slot->ctrl->crit_sect); + 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); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); + 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); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); + 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); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + ctrl_info(ctrl, "Already enabled on slot(%s)\n", + slot_name(p_slot)); + goto out; } - up(&p_slot->ctrl->crit_sect); p_slot->is_a_board = 1; /* We have to save the presence info for these slots */ p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); - dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); + ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - rc = board_added(p_slot); - if (rc) { + if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) || + (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)) + && p_slot->ctrl->num_slots == 1) { + /* handle amd pogo errata; this must be done before enable */ + amd_pogo_errata_save_misc_reg(p_slot); + retval = board_added(p_slot); + /* handle amd pogo errata; this must be done after enable */ + amd_pogo_errata_restore_misc_reg(p_slot); + } else + retval = board_added(p_slot); + + if (retval) { p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); } update_slot_info(p_slot); - return rc; + out: + mutex_unlock(&p_slot->ctrl->crit_sect); + return retval; } -int shpchp_disable_slot (struct slot *p_slot) +static int shpchp_disable_slot (struct slot *p_slot) { u8 getstatus = 0; - int ret = 0; + int rc, retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; if (!p_slot->ctrl) return -ENODEV; /* Check to see if (latch closed, card present, power on) */ - down(&p_slot->ctrl->crit_sect); + mutex_lock(&p_slot->ctrl->crit_sect); - ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (rc || !getstatus) { + ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); + goto out; } - ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (ret || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (rc || getstatus) { + ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); + goto out; } - ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return -ENODEV; + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (rc || !getstatus) { + ctrl_info(ctrl, "Already disabled on slot(%s)\n", + slot_name(p_slot)); + goto out; } - up(&p_slot->ctrl->crit_sect); - ret = remove_board(p_slot); + retval = remove_board(p_slot); update_slot_info(p_slot); - return ret; + out: + mutex_unlock(&p_slot->ctrl->crit_sect); + return retval; } +int shpchp_sysfs_enable_slot(struct slot *p_slot) +{ + int retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; + + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGON_STATE: + cancel_delayed_work(&p_slot->work); + case STATIC_STATE: + p_slot->state = POWERON_STATE; + mutex_unlock(&p_slot->lock); + retval = shpchp_enable_slot(p_slot); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + break; + case POWERON_STATE: + ctrl_info(ctrl, "Slot %s is already in powering on state\n", + slot_name(p_slot)); + break; + case BLINKINGOFF_STATE: + case POWEROFF_STATE: + ctrl_info(ctrl, "Already enabled on slot %s\n", + slot_name(p_slot)); + break; + default: + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); + break; + } + mutex_unlock(&p_slot->lock); + + return retval; +} + +int shpchp_sysfs_disable_slot(struct slot *p_slot) +{ + int retval = -ENODEV; + struct controller *ctrl = p_slot->ctrl; + + mutex_lock(&p_slot->lock); + switch (p_slot->state) { + case BLINKINGOFF_STATE: + cancel_delayed_work(&p_slot->work); + case STATIC_STATE: + p_slot->state = POWEROFF_STATE; + mutex_unlock(&p_slot->lock); + retval = shpchp_disable_slot(p_slot); + mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; + break; + case POWEROFF_STATE: + ctrl_info(ctrl, "Slot %s is already in powering off state\n", + slot_name(p_slot)); + break; + case BLINKINGON_STATE: + case POWERON_STATE: + ctrl_info(ctrl, "Already disabled on slot %s\n", + slot_name(p_slot)); + break; + default: + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); + break; + } + mutex_unlock(&p_slot->lock); + + return retval; +} diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 40905a6c809..29e22352822 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -31,39 +31,9 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/pci.h> -#include "shpchp.h" +#include <linux/interrupt.h> -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ +#include "shpchp.h" /* Slot Available Register I field definition */ #define SLOT_33MHZ 0x0000001f @@ -80,31 +50,6 @@ #define SLOT_100MHZ_PCIX_533 0x0f000000 #define SLOT_133MHZ_PCIX_533 0xf0000000 - -/* Secondary Bus Configuration Register */ -/* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */ -#define PCI_33MHZ 0x0 -#define PCI_66MHZ 0x1 -#define PCIX_66MHZ 0x2 -#define PCIX_100MHZ 0x3 -#define PCIX_133MHZ 0x4 - -/* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */ -#define PCI_33MHZ 0x0 -#define PCI_66MHZ 0x1 -#define PCIX_66MHZ 0x2 -#define PCIX_100MHZ 0x3 -#define PCIX_133MHZ 0x4 -#define PCIX_66MHZ_ECC 0x5 -#define PCIX_100MHZ_ECC 0x6 -#define PCIX_133MHZ_ECC 0x7 -#define PCIX_66MHZ_266 0x9 -#define PCIX_100MHZ_266 0xa -#define PCIX_133MHZ_266 0xb -#define PCIX_66MHZ_533 0x11 -#define PCIX_100MHZ_533 0x12 -#define PCIX_133MHZ_533 0x13 - /* Slot Configuration */ #define SLOT_NUM 0x0000001F #define FIRST_DEV_NUM 0x00001F00 @@ -113,77 +58,94 @@ #define MRLSENSOR 0x40000000 #define ATTN_BUTTON 0x80000000 -/* 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 */ - -/* 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 +/* + * Interrupt Locator Register definitions + */ +#define CMD_INTR_PENDING (1 << 0) +#define SLOT_INTR_PENDING(i) (1 << (i + 1)) -/* 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 +/* + * 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 -/* 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 +/* + * Logical Slot Register definitions + */ +#define SLOT_REG(i) (SLOT1 + (4 * i)) + +#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)) -/* Set bus speed/mode A - 0x40h to 0x47h */ -#define SETA_PCI_33MHZ 0x40 +/* + * SHPC Command Code definitions + * + * 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 @@ -197,1099 +159,753 @@ #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 #define SLOT_SERR_INT_MASK 0x3 -static spinlock_t hpc_event_lock; +static irqreturn_t shpc_isr(int irq, void *dev_id); +static void start_int_poll_timer(struct controller *ctrl, int sec); +static int hpc_check_cmd_status(struct controller *ctrl); + +static inline u8 shpc_readb(struct controller *ctrl, int reg) +{ + return readb(ctrl->creg + reg); +} + +static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) +{ + writeb(val, ctrl->creg + reg); +} + +static inline u16 shpc_readw(struct controller *ctrl, int reg) +{ + return readw(ctrl->creg + reg); +} -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 # */ -static spinlock_t list_lock; +static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) +{ + writew(val, ctrl->creg + reg); +} -static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); +static inline u32 shpc_readl(struct controller *ctrl, int reg) +{ + return readl(ctrl->creg + reg); +} -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); +static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) +{ + writel(val, ctrl->creg + reg); +} -/* This is the interrupt polling timeout function. */ -static void int_poll_timeout(unsigned long lphp_ctlr) +static inline int shpc_indirect_read(struct controller *ctrl, int index, + u32 *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + int rc; + u32 cap_offset = ctrl->cap_offset; + struct pci_dev *pdev = ctrl->pci_dev; - DBG_ENTER_ROUTINE + 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); +} - if ( !php_ctlr ) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } +/* + * This is the interrupt polling timeout function. + */ +static void int_poll_timeout(unsigned long data) +{ + struct controller *ctrl = (struct controller *)data; - /* Poll for interrupt events. regs == NULL => polling */ - shpc_isr( 0, (void *)php_ctlr, NULL ); + /* Poll for interrupt events. regs == NULL => polling */ + shpc_isr(0, ctrl); - init_timer(&php_ctlr->int_poll_timer); + init_timer(&ctrl->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(ctrl, shpchp_poll_time); } -/* 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 controller *ctrl, int sec) { - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; + /* Clamp to sane value */ + if ((sec <= 0) || (sec > 60)) + sec = 2; + + ctrl->poll_timer.function = &int_poll_timeout; + ctrl->poll_timer.data = (unsigned long)ctrl; + ctrl->poll_timer.expires = jiffies + sec * HZ; + add_timer(&ctrl->poll_timer); +} + +static inline int is_ctrl_busy(struct controller *ctrl) +{ + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS); + return cmd_status & 0x1; +} + +/* + * Returns 1 if SHPC finishes executing a command within 1 sec, + * otherwise returns 0. + */ +static inline int shpc_poll_ctrl_busy(struct controller *ctrl) +{ + int i; + + if (!is_ctrl_busy(ctrl)) + return 1; + + /* Check every 0.1 sec for a total of 1 sec */ + for (i = 0; i < 10; i++) { + msleep(100); + if (!is_ctrl_busy(ctrl)) + return 1; } - if ( ( seconds <= 0 ) || ( seconds > 60 ) ) - seconds = 2; /* Clamp to sane value */ + return 0; +} - 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); +static inline int shpc_wait_cmd(struct controller *ctrl) +{ + int retval = 0; + unsigned long timeout = msecs_to_jiffies(1000); + int rc; + + if (shpchp_poll_mode) + rc = shpc_poll_ctrl_busy(ctrl); + else + rc = wait_event_interruptible_timeout(ctrl->queue, + !is_ctrl_busy(ctrl), timeout); + if (!rc && is_ctrl_busy(ctrl)) { + retval = -EIO; + ctrl_err(ctrl, "Command not completed in 1000 msec\n"); + } else if (rc < 0) { + retval = -EINTR; + ctrl_info(ctrl, "Command was interrupted by a signal\n"); + } - return; + return retval; } 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; - int i; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - for (i = 0; i < 10; i++) { - cmd_status = readw(php_ctlr->creg + CMD_STATUS); - - if (!(cmd_status & 0x1)) - break; - /* Check every 0.1 sec for a total of 1 sec*/ - msleep(100); - } + mutex_lock(&slot->ctrl->cmd_lock); - cmd_status = readw(php_ctlr->creg + CMD_STATUS); - - if (cmd_status & 0x1) { + if (!shpc_poll_ctrl_busy(ctrl)) { /* After 1 sec and and the controller is still busy */ - err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); - return -1; + ctrl_err(ctrl, "Controller is still busy after 1 sec\n"); + retval = -EBUSY; + goto out; } ++t_slot; temp_word = (t_slot << 8) | (cmd & 0xFF); - dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); - + ctrl_dbg(ctrl, "%s: t_slot %x cmd %x\n", __func__, t_slot, cmd); + /* To make sure the Controller Busy bit is 0 before we send out the - * command. + * command. */ - writew(temp_word, php_ctlr->creg + CMD); + shpc_writew(ctrl, CMD, temp_word); - DBG_LEAVE_ROUTINE + /* + * Wait for command completion. + */ + retval = shpc_wait_cmd(slot->ctrl); + if (retval) + goto out; + + cmd_status = hpc_check_cmd_status(slot->ctrl); + if (cmd_status) { + ctrl_err(ctrl, "Failed to issued command 0x%x (error code = %d)\n", + cmd, cmd_status); + retval = -EIO; + } + out: + mutex_unlock(&slot->ctrl->cmd_lock); return retval; } 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; + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; - DBG_ENTER_ROUTINE - - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; - switch (cmd_status >> 1) { case 0: retval = 0; break; case 1: retval = SWITCH_OPEN; - err("%s: Switch opened!\n", __FUNCTION__); + ctrl_err(ctrl, "Switch opened!\n"); break; case 2: retval = INVALID_CMD; - err("%s: Invalid HPC command!\n", __FUNCTION__); + ctrl_err(ctrl, "Invalid HPC command!\n"); break; case 4: retval = INVALID_SPEED_MODE; - err("%s: Invalid bus speed/mode!\n", __FUNCTION__); + ctrl_err(ctrl, "Invalid bus speed/mode!\n"); break; default: retval = cmd_status; } - DBG_LEAVE_ROUTINE return retval; } static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg; - u16 slot_status; - u8 atten_led_state; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); - slot_status = (u16) slot_reg; - atten_led_state = (slot_status & 0x0030) >> 4; + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 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; } - DBG_LEAVE_ROUTINE return 0; } -static int hpc_get_power_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; - u32 slot_reg; - u16 slot_status; - u8 slot_state; - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); - slot_status = (u16) slot_reg; - slot_state = (slot_status & 0x0003); + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 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; } static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg; - u16 slot_status; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); - slot_status = (u16)slot_reg; + *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ - *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ - - - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg; - u16 slot_status; - u8 card_state; + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; - DBG_ENTER_ROUTINE + *status = (state != 0x3) ? 1 : 0; - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); - slot_status = (u16)slot_reg; - card_state = (u8)((slot_status & 0x0C00) >> 10); - *status = (card_state != 0x3) ? 1 : 0; - - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + struct controller *ctrl = slot->ctrl; - *prog_int = readb(php_ctlr->creg + PROG_INTERFACE); + *prog_int = shpc_readb(ctrl, PROG_INTERFACE); - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg; - u16 slot_status, sec_bus_status; - u8 m66_cap, pcix_cap, pi; int retval = 0; + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 m66_cap = !!(slot_reg & MHZ66_CAP); + u8 pi, pcix_cap; - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + if ((retval = hpc_get_prog_int(slot, &pi))) + return retval; - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; + 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; } - - pi = readb(php_ctlr->creg + PROG_INTERFACE); - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); - dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg); - slot_status = (u16) slot_reg; - dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status); - sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); - - pcix_cap = (u8) ((slot_status & 0x3000) >> 12); - dbg("%s: pcix_cap = %x\n", __FUNCTION__, pcix_cap); - m66_cap = (u8) ((slot_status & 0x0200) >> 9); - dbg("%s: m66_cap = %x\n", __FUNCTION__, m66_cap); + ctrl_dbg(ctrl, "%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", + __func__, slot_reg, pcix_cap, m66_cap); - if (pi == 2) { - switch (pcix_cap) { - case 0: - *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; - break; - case 1: - *value = PCI_SPEED_66MHz_PCIX; - break; - case 3: - *value = PCI_SPEED_133MHz_PCIX; - break; - case 4: - *value = PCI_SPEED_133MHz_PCIX_266; - break; - case 5: - *value = PCI_SPEED_133MHz_PCIX_533; - break; - case 2: /* Reserved */ - default: - *value = PCI_SPEED_UNKNOWN; - retval = -ENODEV; - break; - } - } else { - switch (pcix_cap) { - case 0: - *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; - break; - case 1: - *value = PCI_SPEED_66MHz_PCIX; - break; - case 3: - *value = PCI_SPEED_133MHz_PCIX; - break; - case 2: /* Reserved */ - default: - *value = PCI_SPEED_UNKNOWN; - retval = -ENODEV; - break; - } + switch (pcix_cap) { + case 0x0: + *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + break; + case 0x1: + *value = PCI_SPEED_66MHz_PCIX; + break; + case 0x3: + *value = PCI_SPEED_133MHz_PCIX; + break; + case 0x4: + *value = PCI_SPEED_133MHz_PCIX_266; + break; + case 0x5: + *value = PCI_SPEED_133MHz_PCIX_533; + break; + case 0x2: + default: + *value = PCI_SPEED_UNKNOWN; + retval = -ENODEV; + break; } - dbg("Adapter speed = %d\n", *value); - - DBG_LEAVE_ROUTINE + ctrl_dbg(ctrl, "Adapter speed = %d\n", *value); return retval; } static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u16 sec_bus_status; - u8 pi; int retval = 0; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - pi = readb(php_ctlr->creg + PROG_INTERFACE); - sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + struct controller *ctrl = slot->ctrl; + u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); if (pi == 2) { - *mode = (sec_bus_status & 0x0100) >> 7; + *mode = (sec_bus_status & 0x0100) >> 8; } else { retval = -1; } - dbg("Mode 1 ECC cap = %d\n", *mode); - - DBG_LEAVE_ROUTINE + ctrl_dbg(ctrl, "Mode 1 ECC cap = %d\n", *mode); return retval; } -static int hpc_query_power_fault(struct slot * slot) +static int hpc_query_power_fault(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u32 slot_reg; - u16 slot_status; - u8 pwr_fault_state, status; - - DBG_ENTER_ROUTINE + struct controller *ctrl = slot->ctrl; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(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) { - 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 : - slot_cmd = 0x30; /* OFF */ + case 0 : + 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; } - 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, SET_PWR_ON); } 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, SET_PWR_OFF); } 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; -} - -int shpc_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, /* number of slots in this HPC */ - int *first_device_num, /* PCI dev num of the first slot in this SHPC */ - int *physical_slot_num, /* phy slot num of the first slot in this SHPC */ - int *updown, /* physical_slot_num increament: 1 or -1 */ - int *flags) -{ - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - - DBG_ENTER_ROUTINE - - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - 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() */ - - *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; + shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK); } 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; - - DBG_ENTER_ROUTINE + int i; + u32 slot_reg, serr_int; - if (!ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; + /* + * Mask event interrupts and SERRs of all slots + */ + 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); } - if (shpchp_poll_mode) { - del_timer(&php_ctlr->int_poll_timer); - } else { - if (php_ctlr->irq) { - free_irq(php_ctlr->irq, ctrl); - php_ctlr->irq = 0; - pci_disable_msi(php_ctlr->pci_dev); - } - } - if (php_ctlr->pci_dev) { - iounmap(php_ctlr->creg); - release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); - php_ctlr->pci_dev = NULL; - } + cleanup_slots(ctrl); - spin_lock(&list_lock); - p = php_ctlr_list_head; - p_prev = NULL; - while (p) { - if (p == php_ctlr) { - if (p_prev) - p_prev->pnext = p->pnext; - else - php_ctlr_list_head = p->pnext; - break; - } else { - p_prev = p; - p = p->pnext; - } - } - spin_unlock(&list_lock); + /* + * Mask SERR and System Interrupt 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); - kfree(php_ctlr); + if (shpchp_poll_mode) + del_timer(&ctrl->poll_timer); + else { + free_irq(ctrl->pci_dev->irq, ctrl); + pci_disable_msi(ctrl->pci_dev); + } -DBG_LEAVE_ROUTINE - + iounmap(ctrl->creg); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); } -static int hpc_power_on_slot(struct slot * slot) +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); - - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - - DBG_LEAVE_ROUTINE + retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); + if (retval) + ctrl_err(slot->ctrl, "%s: Write command failed!\n", __func__); return retval; } -static int hpc_slot_enable(struct slot * slot) +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; - - DBG_ENTER_ROUTINE + int retval; - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + /* 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) + ctrl_err(slot->ctrl, "%s: Write command failed!\n", __func__); - 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; + return retval; +} - retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); +static int hpc_slot_disable(struct slot *slot) +{ + int retval; - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } + /* 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) + ctrl_err(slot->ctrl, "%s: Write command failed!\n", __func__); - DBG_LEAVE_ROUTINE return retval; } -static int hpc_slot_disable(struct slot * slot) +static int shpc_get_cur_bus_speed(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - u8 slot_cmd; int retval = 0; + struct pci_bus *bus = ctrl->pci_dev->subordinate; + enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; + 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 - - 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; + if ((pi == 1) && (speed_mode > 4)) { + retval = -ENODEV; + goto out; } - /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ - slot_cmd = 0x1F; - - retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); - - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; + switch (speed_mode) { + case 0x0: + bus_speed = PCI_SPEED_33MHz; + break; + case 0x1: + bus_speed = PCI_SPEED_66MHz; + break; + case 0x2: + bus_speed = PCI_SPEED_66MHz_PCIX; + break; + case 0x3: + bus_speed = PCI_SPEED_100MHz_PCIX; + break; + case 0x4: + bus_speed = PCI_SPEED_133MHz_PCIX; + break; + case 0x5: + bus_speed = PCI_SPEED_66MHz_PCIX_ECC; + break; + case 0x6: + bus_speed = PCI_SPEED_100MHz_PCIX_ECC; + break; + case 0x7: + bus_speed = PCI_SPEED_133MHz_PCIX_ECC; + break; + case 0x8: + bus_speed = PCI_SPEED_66MHz_PCIX_266; + break; + case 0x9: + bus_speed = PCI_SPEED_100MHz_PCIX_266; + break; + case 0xa: + bus_speed = PCI_SPEED_133MHz_PCIX_266; + break; + case 0xb: + bus_speed = PCI_SPEED_66MHz_PCIX_533; + break; + case 0xc: + bus_speed = PCI_SPEED_100MHz_PCIX_533; + break; + case 0xd: + bus_speed = PCI_SPEED_133MHz_PCIX_533; + break; + default: + retval = -ENODEV; + break; } - DBG_LEAVE_ROUTINE + out: + bus->cur_bus_speed = bus_speed; + dbg("Current bus speed = %d\n", bus_speed); return retval; } -static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) -{ - u8 slot_cmd; - u8 pi; - int retval = 0; - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } +static int hpc_set_bus_speed_mode(struct slot *slot, enum pci_bus_speed value) +{ + int retval; + struct controller *ctrl = slot->ctrl; + u8 pi, cmd; - pi = readb(php_ctlr->creg + PROG_INTERFACE); - - if (pi == 1) { - switch (value) { - case 0: - slot_cmd = SETA_PCI_33MHZ; - break; - case 1: - slot_cmd = SETA_PCI_66MHZ; - break; - case 2: - slot_cmd = SETA_PCIX_66MHZ; - break; - case 3: - slot_cmd = SETA_PCIX_100MHZ; - break; - case 4: - slot_cmd = SETA_PCIX_133MHZ; - break; - default: - slot_cmd = PCI_SPEED_UNKNOWN; - retval = -ENODEV; - return retval; - } - } else { - switch (value) { - case 0: - slot_cmd = SETB_PCI_33MHZ; - break; - case 1: - slot_cmd = SETB_PCI_66MHZ; - break; - case 2: - slot_cmd = SETB_PCIX_66MHZ_PM; - break; - case 3: - slot_cmd = SETB_PCIX_100MHZ_PM; - break; - case 4: - slot_cmd = SETB_PCIX_133MHZ_PM; - break; - case 5: - slot_cmd = SETB_PCIX_66MHZ_EM; - break; - case 6: - slot_cmd = SETB_PCIX_100MHZ_EM; - break; - case 7: - slot_cmd = SETB_PCIX_133MHZ_EM; - break; - case 8: - slot_cmd = SETB_PCIX_66MHZ_266; - break; - case 0x9: - slot_cmd = SETB_PCIX_100MHZ_266; - break; - case 0xa: - slot_cmd = SETB_PCIX_133MHZ_266; - break; - case 0xb: - slot_cmd = SETB_PCIX_66MHZ_533; - break; - case 0xc: - slot_cmd = SETB_PCIX_100MHZ_533; - break; - case 0xd: - slot_cmd = SETB_PCIX_133MHZ_533; - break; - default: - slot_cmd = PCI_SPEED_UNKNOWN; - retval = -ENODEV; - return retval; - } + pi = shpc_readb(ctrl, PROG_INTERFACE); + if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) + return -EINVAL; + switch (value) { + case PCI_SPEED_33MHz: + cmd = SETA_PCI_33MHZ; + break; + case PCI_SPEED_66MHz: + cmd = SETA_PCI_66MHZ; + break; + case PCI_SPEED_66MHz_PCIX: + cmd = SETA_PCIX_66MHZ; + break; + case PCI_SPEED_100MHz_PCIX: + cmd = SETA_PCIX_100MHZ; + break; + case PCI_SPEED_133MHz_PCIX: + cmd = SETA_PCIX_133MHZ; + break; + case PCI_SPEED_66MHz_PCIX_ECC: + cmd = SETB_PCIX_66MHZ_EM; + break; + case PCI_SPEED_100MHz_PCIX_ECC: + cmd = SETB_PCIX_100MHZ_EM; + break; + case PCI_SPEED_133MHz_PCIX_ECC: + cmd = SETB_PCIX_133MHZ_EM; + break; + case PCI_SPEED_66MHz_PCIX_266: + cmd = SETB_PCIX_66MHZ_266; + break; + case PCI_SPEED_100MHz_PCIX_266: + cmd = SETB_PCIX_100MHZ_266; + break; + case PCI_SPEED_133MHz_PCIX_266: + cmd = SETB_PCIX_133MHZ_266; + break; + case PCI_SPEED_66MHz_PCIX_533: + cmd = SETB_PCIX_66MHZ_533; + break; + case PCI_SPEED_100MHz_PCIX_533: + cmd = SETB_PCIX_100MHZ_533; + break; + case PCI_SPEED_133MHz_PCIX_533: + cmd = SETB_PCIX_133MHZ_533; + break; + default: + return -EINVAL; } - retval = shpc_write_cmd(slot, 0, slot_cmd); - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - DBG_LEAVE_ROUTINE + retval = shpc_write_cmd(slot, 0, cmd); + if (retval) + ctrl_err(ctrl, "%s: Write command failed!\n", __func__); + else + shpc_get_cur_bus_speed(ctrl); + 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 controller *ctrl = NULL; - struct php_ctlr_state_s *php_ctlr; - u8 schedule_flag = 0; - u8 temp_byte; - u32 temp_dword, intr_loc, intr_loc2; + struct controller *ctrl = (struct controller *)dev_id; + 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 = readl(php_ctlr->creg + INTR_LOC); - + intr_loc = shpc_readl(ctrl, INTR_LOC); if (!intr_loc) return IRQ_NONE; - dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); + + ctrl_dbg(ctrl, "%s: intr_loc = %x\n", __func__, intr_loc); 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 |= 0x00000001; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); - - intr_loc2 = readl(php_ctlr->creg + INTR_LOC); - dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); + /* + * 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); + ctrl_dbg(ctrl, "%s: intr_loc2 = %x\n", __func__, intr_loc2); } - if (intr_loc & 0x0001) { - /* - * Command Complete Interrupt Pending - * RO only - clear by writing 0 to the Command Completion + 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 = readl(php_ctlr->creg + SERR_INTR_ENABLE); - temp_dword &= 0xfffeffff; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); + serr_int &= ~SERR_INTR_RSVDZ_MASK; + shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); + wake_up_interruptible(&ctrl->queue); } - if ((intr_loc = (intr_loc >> 1)) == 0) { - /* Unmask Global Interrupt Mask */ - temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - temp_dword &= 0xfffffffe; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + if (!(intr_loc & ~CMD_INTR_PENDING)) + goto out; - return IRQ_NONE; - } + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + /* To find out which slot has interrupt pending */ + if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) + continue; - 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)); - 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)) - schedule_flag += php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) - schedule_flag += php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) - schedule_flag += php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12)) - schedule_flag += php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); - - /* Clear all slot events */ - temp_dword = 0xe01f3fff; - writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); - - intr_loc2 = readl(php_ctlr->creg + INTR_LOC); - dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); - } - } - if (!shpchp_poll_mode) { - /* Unmask Global Interrupt Mask */ - temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - temp_dword &= 0xfffffffe; - writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); - } - - return IRQ_HANDLED; -} - -static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) -{ - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; - int retval = 0; - u8 pi; - u32 slot_avail1, slot_avail2; - int slot_num; + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); + ctrl_dbg(ctrl, "Slot %x with intr, slot register = %x\n", + hp_slot, slot_reg); - DBG_ENTER_ROUTINE + if (slot_reg & MRL_CHANGE_DETECTED) + shpchp_handle_switch_change(hp_slot, ctrl); - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } + if (slot_reg & BUTTON_PRESS_DETECTED) + shpchp_handle_attention_button(hp_slot, ctrl); - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } + if (slot_reg & PRSNT_CHANGE_DETECTED) + shpchp_handle_presence_change(hp_slot, ctrl); - pi = readb(php_ctlr->creg + PROG_INTERFACE); - slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); - slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); + if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) + shpchp_handle_power_fault(hp_slot, ctrl); - if (pi == 2) { - if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27) ) != 0 ) - bus_speed = PCIX_133MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23) ) != 0 ) - bus_speed = PCIX_100MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19) ) != 0 ) - bus_speed = PCIX_66MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15) ) != 0 ) - bus_speed = PCIX_133MHZ_266; - else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11) ) != 0 ) - bus_speed = PCIX_100MHZ_266; - else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7) ) != 0 ) - bus_speed = PCIX_66MHZ_266; - else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) - bus_speed = PCIX_133MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) - bus_speed = PCIX_100MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) - bus_speed = PCIX_66MHZ; - else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) - bus_speed = PCI_66MHZ; - else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) - bus_speed = PCI_33MHZ; - else bus_speed = PCI_SPEED_UNKNOWN; - } else { - if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) - bus_speed = PCIX_133MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) - bus_speed = PCIX_100MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) - bus_speed = PCIX_66MHZ; - else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) - bus_speed = PCI_66MHZ; - else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) - bus_speed = PCI_33MHZ; - else bus_speed = PCI_SPEED_UNKNOWN; + /* 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 */ + 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); } - *value = bus_speed; - dbg("Max bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE - return retval; + return IRQ_HANDLED; } -static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) +static int shpc_get_max_bus_speed(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; - enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; - u16 sec_bus_status; int retval = 0; - u8 pi; - - 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; - } - - pi = readb(php_ctlr->creg + PROG_INTERFACE); - sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + struct pci_bus *bus = ctrl->pci_dev->subordinate; + enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); + u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); + u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); if (pi == 2) { - switch (sec_bus_status & 0x000f) { - case 0: - bus_speed = PCI_SPEED_33MHz; - break; - case 1: - bus_speed = PCI_SPEED_66MHz; - break; - case 2: + if (slot_avail2 & SLOT_133MHZ_PCIX_533) + bus_speed = PCI_SPEED_133MHz_PCIX_533; + else if (slot_avail2 & SLOT_100MHZ_PCIX_533) + bus_speed = PCI_SPEED_100MHz_PCIX_533; + else if (slot_avail2 & SLOT_66MHZ_PCIX_533) + bus_speed = PCI_SPEED_66MHz_PCIX_533; + else if (slot_avail2 & SLOT_133MHZ_PCIX_266) + bus_speed = PCI_SPEED_133MHz_PCIX_266; + else if (slot_avail2 & SLOT_100MHZ_PCIX_266) + bus_speed = PCI_SPEED_100MHz_PCIX_266; + else if (slot_avail2 & SLOT_66MHZ_PCIX_266) + bus_speed = PCI_SPEED_66MHz_PCIX_266; + } + + if (bus_speed == PCI_SPEED_UNKNOWN) { + if (slot_avail1 & SLOT_133MHZ_PCIX) + bus_speed = PCI_SPEED_133MHz_PCIX; + else if (slot_avail1 & SLOT_100MHZ_PCIX) + bus_speed = PCI_SPEED_100MHz_PCIX; + else if (slot_avail1 & SLOT_66MHZ_PCIX) bus_speed = PCI_SPEED_66MHz_PCIX; - break; - case 3: - bus_speed = PCI_SPEED_100MHz_PCIX; - break; - case 4: - bus_speed = PCI_SPEED_133MHz_PCIX; - break; - case 5: - bus_speed = PCI_SPEED_66MHz_PCIX_ECC; - break; - case 6: - bus_speed = PCI_SPEED_100MHz_PCIX_ECC; - break; - case 7: - bus_speed = PCI_SPEED_133MHz_PCIX_ECC; - break; - case 8: - bus_speed = PCI_SPEED_66MHz_PCIX_266; - break; - case 9: - bus_speed = PCI_SPEED_100MHz_PCIX_266; - break; - case 0xa: - bus_speed = PCI_SPEED_133MHz_PCIX_266; - break; - case 0xb: - bus_speed = PCI_SPEED_66MHz_PCIX_533; - break; - case 0xc: - bus_speed = PCI_SPEED_100MHz_PCIX_533; - break; - case 0xd: - bus_speed = PCI_SPEED_133MHz_PCIX_533; - break; - case 0xe: - case 0xf: - default: - bus_speed = PCI_SPEED_UNKNOWN; - break; - } - } else { - /* In the case where pi is undefined, default it to 1 */ - switch (sec_bus_status & 0x0007) { - case 0: - bus_speed = PCI_SPEED_33MHz; - break; - case 1: + else if (slot_avail2 & SLOT_66MHZ) bus_speed = PCI_SPEED_66MHz; - break; - case 2: - bus_speed = PCI_SPEED_66MHz_PCIX; - break; - case 3: - bus_speed = PCI_SPEED_100MHz_PCIX; - break; - case 4: - bus_speed = PCI_SPEED_133MHz_PCIX; - break; - case 5: - bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ - break; - case 6: - bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ - break; - case 7: - bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ - break; - default: - bus_speed = PCI_SPEED_UNKNOWN; - break; - } + else if (slot_avail1 & SLOT_33MHZ) + bus_speed = PCI_SPEED_33MHz; + else + retval = -ENODEV; } - *value = bus_speed; - dbg("Current bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE + bus->max_bus_speed = bus_speed; + ctrl_dbg(ctrl, "Max bus speed = %d\n", bus_speed); + return retval; } @@ -1297,15 +913,13 @@ static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, - .set_bus_speed_mode = hpc_set_bus_speed_mode, + .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, - .get_max_bus_speed = hpc_get_max_bus_speed, - .get_cur_bus_speed = hpc_get_cur_bus_speed, .get_adapter_speed = hpc_get_adapter_speed, .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap, .get_prog_int = hpc_get_prog_int, @@ -1314,206 +928,183 @@ static struct hpc_ops shpchp_hpc_ops = { .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, - .check_cmd_status = hpc_check_cmd_status, }; -int shpc_init(struct controller * ctrl, struct pci_dev * pdev) +int shpc_init(struct controller *ctrl, struct pci_dev *pdev) { - struct php_ctlr_state_s *php_ctlr, *p; - void *instance_id = ctrl; - int rc; + int rc = -1, num_slots = 0; u8 hp_slot; - static int first = 1; - u32 shpc_cap_offset, shpc_base_offset; - u32 tempdword, slot_reg; + u32 shpc_base_offset; + u32 tempdword, slot_reg, slot_config; u8 i; - DBG_ENTER_ROUTINE - - spin_lock_init(&list_lock); - php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); - - if (!php_ctlr) { /* allocate controller state data */ - err("%s: HPC controller memory allocation error!\n", __FUNCTION__); - goto abort; - } - - memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); + ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ + ctrl_dbg(ctrl, "Hotplug Controller:\n"); - php_ctlr->pci_dev = pdev; /* save pci_dev in context */ - - if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) { - shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ + if (pdev->vendor == PCI_VENDOR_ID_AMD && + pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) { + /* amd shpc driver doesn't use Base Offset; assume 0 */ + ctrl->mmio_base = pci_resource_start(pdev, 0); + ctrl->mmio_size = pci_resource_len(pdev, 0); } else { - if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { - err("%s : shpc_cap_offset == 0\n", __FUNCTION__); - goto abort_free_ctlr; + ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); + if (!ctrl->cap_offset) { + ctrl_err(ctrl, "Cannot find PCI capability\n"); + goto abort; } - dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset); - - rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET); + ctrl_dbg(ctrl, " cap_offset = %x\n", ctrl->cap_offset); + + rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); if (rc) { - err("%s : pci_word_config_byte failed\n", __FUNCTION__); - goto abort_free_ctlr; + ctrl_err(ctrl, "Cannot read base_offset\n"); + goto abort; } - - rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset); + + rc = shpc_indirect_read(ctrl, 3, &tempdword); if (rc) { - err("%s : pci_read_config_dword failed\n", __FUNCTION__); - goto abort_free_ctlr; + ctrl_err(ctrl, "Cannot read slot config\n"); + goto abort; } + num_slots = tempdword & SLOT_NUM; + ctrl_dbg(ctrl, " num_slots (indirect) %x\n", num_slots); - for (i = 0; i <= 14; i++) { - rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i); + for (i = 0; i < 9 + num_slots; i++) { + rc = shpc_indirect_read(ctrl, i, &tempdword); if (rc) { - err("%s : pci_word_config_byte failed\n", __FUNCTION__); - goto abort_free_ctlr; + ctrl_err(ctrl, "Cannot read creg (index = %d)\n", + i); + goto abort; } - - rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword); - if (rc) { - err("%s : pci_read_config_dword failed\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: offset %d: value %x\n", __FUNCTION__,i, - tempdword); + ctrl_dbg(ctrl, " offset %d: value %x\n", i, tempdword); } - } - if (first) { - spin_lock_init(&hpc_event_lock); - first = 0; + ctrl->mmio_base = + pci_resource_start(pdev, 0) + shpc_base_offset; + ctrl->mmio_size = 0x24 + 0x4 * num_slots; } - 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; + ctrl_info(ctrl, "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 (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) { - err("%s: cannot reserve MMIO region\n", __FUNCTION__); - goto abort_free_ctlr; + rc = pci_enable_device(pdev); + if (rc) { + ctrl_err(ctrl, "pci_enable_device failed\n"); + goto abort; } - php_ctlr->creg = ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); - if (!php_ctlr->creg) { - err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), - pci_resource_start(pdev, 0) + shpc_base_offset); - release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); - goto abort_free_ctlr; + if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { + ctrl_err(ctrl, "Cannot reserve MMIO region\n"); + rc = -1; + goto abort; + } + + ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); + if (!ctrl->creg) { + ctrl_err(ctrl, "Cannot remap MMIO region %lx @ %lx\n", + ctrl->mmio_size, ctrl->mmio_base); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); + rc = -1; + goto abort; } - dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); + ctrl_dbg(ctrl, "ctrl->creg %p\n", ctrl->creg); + + mutex_init(&ctrl->crit_sect); + mutex_init(&ctrl->cmd_lock); - init_MUTEX(&ctrl->crit_sect); /* Setup wait queue */ init_waitqueue_head(&ctrl->queue); - /* Find the IRQ */ - php_ctlr->irq = pdev->irq; - php_ctlr->attention_button_callback = shpchp_handle_attention_button, - php_ctlr->switch_change_callback = shpchp_handle_switch_change; - php_ctlr->presence_change_callback = shpchp_handle_presence_change; - php_ctlr->power_fault_callback = shpchp_handle_power_fault; - php_ctlr->callback_instance_id = instance_id; + 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; - dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); - dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); + slot_config = shpc_readl(ctrl, SLOT_CONFIG); + ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; + ctrl->num_slots = slot_config & SLOT_NUM; + ctrl->first_slot = (slot_config & PSN) >> 16; + ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1; /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ - tempdword = readl(php_ctlr->creg + 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); - dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); + ctrl_dbg(ctrl, "SERR_INTR_ENABLE = %x\n", tempdword); + 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); + ctrl_dbg(ctrl, "SERR_INTR_ENABLE = %x\n", 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 ); - 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)); + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); + ctrl_dbg(ctrl, "Default Logical Slot Register %d value %x\n", + hp_slot, slot_reg); + 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 */ - /* Install and start the interrupt polling timer */ - init_timer(&php_ctlr->int_poll_timer); - start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + + if (shpchp_poll_mode) { + /* Install interrupt polling timer. Start with 10 sec delay */ + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); } else { /* Installs the interrupt handler */ rc = pci_enable_msi(pdev); if (rc) { - info("Can't get msi for the hotplug controller\n"); - info("Use INTx for the hotplug controller\n"); - } else - php_ctlr->irq = pdev->irq; - - rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); - if (rc) { - err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); - goto abort_free_ctlr; + ctrl_info(ctrl, "Can't get msi for the hotplug controller\n"); + ctrl_info(ctrl, "Use INTx for the hotplug controller\n"); } - } - dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, - pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq); - get_hp_hw_control_from_firmware(pdev); - - /* Add this HPC instance into the HPC list */ - spin_lock(&list_lock); - if (php_ctlr_list_head == 0) { - php_ctlr_list_head = php_ctlr; - p = php_ctlr_list_head; - p->pnext = NULL; - } else { - p = php_ctlr_list_head; - - while (p->pnext) - p = p->pnext; - p->pnext = php_ctlr; + rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, + MY_NAME, (void *)ctrl); + ctrl_dbg(ctrl, "request_irq %d (returns %d)\n", + ctrl->pci_dev->irq, rc); + if (rc) { + ctrl_err(ctrl, "Can't get irq %d for the hotplug controller\n", + ctrl->pci_dev->irq); + goto abort_iounmap; + } } - spin_unlock(&list_lock); - + ctrl_dbg(ctrl, "HPC at %s irq=%x\n", pci_name(pdev), pdev->irq); - ctlr_seq_num++; - ctrl->hpc_ctlr_handle = php_ctlr; - ctrl->hpc_ops = &shpchp_hpc_ops; + shpc_get_max_bus_speed(ctrl); + shpc_get_cur_bus_speed(ctrl); - for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { - slot_reg = readl(php_ctlr->creg + 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)); + /* + * Unmask all event interrupts of all slots + */ + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); + ctrl_dbg(ctrl, "Default Logical Slot Register %d value %x\n", + hp_slot, slot_reg); + 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 */ - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - tempdword = 0x0000000a; - writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); - tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); + tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); + 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); + ctrl_dbg(ctrl, "SERR_INTR_ENABLE = %x\n", tempdword); } - DBG_LEAVE_ROUTINE return 0; /* We end up here for the many possible ways to fail this API. */ -abort_free_ctlr: - kfree(php_ctlr); +abort_iounmap: + iounmap(ctrl->creg); abort: - DBG_LEAVE_ROUTINE - return -1; + return rc; } diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index b8e95acea3b..469454e0cc4 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -34,144 +34,89 @@ #include "../pci.h" #include "shpchp.h" -void program_fw_provided_values(struct pci_dev *dev) -{ - u16 pci_cmd, pci_bctl; - struct pci_dev *cdev; - struct hotplug_params hpp = {0x8, 0x40, 0, 0}; /* defaults */ - - /* 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; - - get_hp_params_from_firmware(dev, &hpp); - - 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 and child devices */ - 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); - if (dev->subordinate) { - list_for_each_entry(cdev, &dev->subordinate->devices, - bus_list) - program_fw_provided_values(cdev); - } - } -} - int shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; - struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; - int num, fn; + struct controller *ctrl = p_slot->ctrl; + struct pci_dev *bridge = ctrl->pci_dev; + struct pci_bus *parent = bridge->subordinate; + int num, ret = 0; - dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); + pci_lock_rescan_remove(); + + 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); - return -EINVAL; + ctrl_err(ctrl, "Device %s already exists at %04x:%02x:%02x, cannot hot-add\n", + pci_name(dev), pci_domain_nr(parent), + p_slot->bus, p_slot->device); + pci_dev_put(dev); + ret = -EINVAL; + goto out; } num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); if (num == 0) { - err("No new device found\n"); - return -ENODEV; + ctrl_err(ctrl, "No new device found\n"); + ret = -ENODEV; + goto out; } - for (fn = 0; fn < 8; fn++) { - if (!(dev = pci_find_slot(p_slot->bus, - PCI_DEVFN(p_slot->device, fn)))) + list_for_each_entry(dev, &parent->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != p_slot->device) continue; - if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - err("Cannot hot-add display device %s\n", - pci_name(dev)); + if (pci_is_bridge(dev)) + pci_hp_add_bridge(dev); + } + + pci_assign_unassigned_bridge_resources(bridge); + + list_for_each_entry(dev, &parent->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != p_slot->device) continue; - } - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { - /* Find an unused bus number for the new bridge */ - struct pci_bus *child; - unsigned char busnr, start = parent->secondary; - unsigned char end = parent->subordinate; - for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), - busnr)) - break; - } - if (busnr >= end) { - err("No free bus for hot-added bridge\n"); - continue; - } - child = pci_add_new_bus(parent, dev, busnr); - if (!child) { - err("Cannot add new bus for %s\n", - pci_name(dev)); - continue; - } - child->subordinate = pci_do_scan_bus(child); - pci_bus_size_bridges(child); - } - program_fw_provided_values(dev); + pci_configure_slot(dev); } - pci_bus_assign_resources(parent); pci_bus_add_devices(parent); - pci_enable_bridges(parent); - return 0; + + out: + pci_unlock_rescan_remove(); + return ret; } int shpchp_unconfigure_device(struct slot *p_slot) { int rc = 0; - int j; u8 bctl = 0; - - dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); + struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + struct pci_dev *dev, *temp; + struct controller *ctrl = p_slot->ctrl; - for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(p_slot->bus, - (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)); + ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", + __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); + + pci_lock_rescan_remove(); + + list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != p_slot->device) continue; - } - if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + + pci_dev_get(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", - pci_name(temp)); - continue; + ctrl_err(ctrl, + "Cannot remove display device %s\n", + pci_name(dev)); + pci_dev_put(dev); + rc = -EINVAL; + break; } } - pci_remove_bus_device(temp); + pci_stop_and_remove_bus_device(dev); + pci_dev_put(dev); } + + pci_unlock_rescan_remove(); return rc; } diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index f5cfbf2c047..52875b36046 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -38,7 +38,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; - char * out = buf; + char *out = buf; int index, busnr; struct resource *res; struct pci_bus *bus; @@ -47,47 +47,47 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha bus = pdev->subordinate; out += sprintf(buf, "Free resources: memory\n"); - for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { - res = bus->resource[index]; + pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && !(res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: prefetchable memory\n"); - for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { - res = bus->resource[index]; + pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && (res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: IO\n"); - for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { - res = bus->resource[index]; + pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_IO)) { - out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", - res->start, (res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: bus numbers\n"); - for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { + for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) { if (!pci_find_bus(pci_domain_nr(bus), busnr)) break; } - if (busnr < bus->subordinate) + if (busnr < bus->busn_res.end) out += sprintf(out, "start = %8.8x, length = %8.8x\n", - busnr, (bus->subordinate - busnr)); + busnr, (int)(bus->busn_res.end - busnr)); return out - buf; } static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -void shpchp_create_ctrl_files (struct controller *ctrl) +int shpchp_create_ctrl_files (struct controller *ctrl) { - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); + return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); } void shpchp_remove_ctrl_files(struct controller *ctrl) diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c deleted file mode 100644 index 17145e52223..00000000000 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform - * - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <kristen.c.accardi@intel.com> - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/actypes.h> -#include "shpchp.h" - -#define METHOD_NAME__SUN "_SUN" -#define METHOD_NAME__HPP "_HPP" -#define METHOD_NAME_OSHP "OSHP" - -static u8 * acpi_path_name( acpi_handle handle) -{ - acpi_status status; - static u8 path_name[ACPI_PATHNAME_MAX]; - struct acpi_buffer ret_buf = { ACPI_PATHNAME_MAX, path_name }; - - memset(path_name, 0, sizeof (path_name)); - status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf); - - if (ACPI_FAILURE(status)) - return NULL; - else - return path_name; -} - -static acpi_status -acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) -{ - acpi_status status; - u8 nui[4]; - struct acpi_buffer ret_buf = { 0, NULL}; - union acpi_object *ext_obj, *package; - u8 *path_name = acpi_path_name(handle); - int i, len = 0; - - /* get _hpp */ - status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); - switch (status) { - case AE_BUFFER_OVERFLOW: - ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); - if (!ret_buf.pointer) { - err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, - path_name); - return AE_NO_MEMORY; - } - status = acpi_evaluate_object(handle, METHOD_NAME__HPP, - NULL, &ret_buf); - if (ACPI_SUCCESS(status)) - break; - default: - if (ACPI_FAILURE(status)) { - dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, - path_name, status); - return status; - } - } - - ext_obj = (union acpi_object *) ret_buf.pointer; - if (ext_obj->type != ACPI_TYPE_PACKAGE) { - err ("%s:%s _HPP obj not a package\n", __FUNCTION__, - path_name); - status = AE_ERROR; - goto free_and_return; - } - - len = ext_obj->package.count; - package = (union acpi_object *) ret_buf.pointer; - for ( i = 0; (i < len) || (i < 4); i++) { - ext_obj = (union acpi_object *) &package->package.elements[i]; - switch (ext_obj->type) { - case ACPI_TYPE_INTEGER: - nui[i] = (u8)ext_obj->integer.value; - break; - default: - err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, - path_name); - status = AE_ERROR; - goto free_and_return; - } - } - - hpp->cache_line_size = nui[0]; - hpp->latency_timer = nui[1]; - hpp->enable_serr = nui[2]; - hpp->enable_perr = nui[3]; - - dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); - -free_and_return: - kfree(ret_buf.pointer); - return status; -} - -static void acpi_run_oshp(acpi_handle handle) -{ - acpi_status status; - u8 *path_name = acpi_path_name(handle); - - /* run OSHP */ - status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); - if (ACPI_FAILURE(status)) { - err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, - status); - } else { - dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); - } -} - -int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) -{ - int offset = devnum - ctrl->slot_device_offset; - - dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset); - *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset); - return 0; -} - -void get_hp_hw_control_from_firmware(struct pci_dev *dev) -{ - /* - * OSHP is an optional ACPI firmware control method. If present, - * we need to run it to inform BIOS that we will control SHPC - * hardware from now on. - */ - acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); - if (!handle) - return; - acpi_run_oshp(handle); -} - -void get_hp_params_from_firmware(struct pci_dev *dev, - struct hotplug_params *hpp) -{ - acpi_status status = AE_NOT_FOUND; - struct pci_dev *pdev = dev; - - /* - * _HPP settings apply to all child buses, until another _HPP is - * encountered. If we don't find an _HPP for the input pci 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; - status = acpi_run_hpp(handle, hpp); - if (!(pdev->bus->parent)) - break; - /* Check if a parent object supports _HPP */ - pdev = pdev->bus->parent->self; - } -} - diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c deleted file mode 100644 index ed6c1254bf6..00000000000 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include "shpchp.h" - -int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) -{ - int offset = devnum - ctrl->slot_device_offset; - - *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset); - return 0; -} - -void get_hp_params_from_firmware(struct pci_dev *dev, - struct hotplug_params *hpp) -{ - return; -} - -void get_hp_hw_control_from_firmware(struct pci_dev *dev) -{ - return; -} - diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c deleted file mode 100644 index c6b40998eeb..00000000000 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/slab.h> - -#include "shpchp.h" - -int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) -{ - int offset = devnum - ctrl->slot_device_offset; - - dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset); - *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset); - return 0; -} - -void get_hp_params_from_firmware(struct pci_dev *dev, - struct hotplug_params *hpp) -{ - return; -} - -void get_hp_hw_control_from_firmware(struct pci_dev *dev) -{ - return; -} |
