From patchwork Tue Aug 13 07:24:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Hellwig X-Patchwork-Id: 1146065 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-ide-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=lst.de Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=infradead.org header.i=@infradead.org header.b="B6rYrLcZ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46746x18NYz9sNm for ; Tue, 13 Aug 2019 17:27:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727657AbfHMHZe (ORCPT ); Tue, 13 Aug 2019 03:25:34 -0400 Received: from bombadil.infradead.org ([198.137.202.133]:50088 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725820AbfHMHZe (ORCPT ); Tue, 13 Aug 2019 03:25:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender :Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From :Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=OjylB7vTSBwoqsWZlXTFpvn4sVDuHvPB8r+V3DC4Dgc=; b=B6rYrLcZiO51cQrWmcDiDEhEgk rpzrHaJVPtIKATC5sesGdZDmCH4spU2i7vMfQwf+kem9GksIEF3ffNGmdRENVxQfRwzG3+3yMkRBS 1Yc7d+iN9OF1X8Q7uUxFmBcaHYDxmbTHLJE18tqJCjfXR5TnMRJK5WAHd13VSsRoiQ+zMIdh7fmKg Qy1jebjStcdmTgbDn+xNE00QA1mIi/ZYsDGoSikU5bCCIlm4iRS0lEcBu5SSM29i4pMCNoZR4bOiB cIQ60P783qKxjY5lj9nWo0GRKx2FGFUCeOVf0QH20WkCUbyomyku+z1Q3/1CjD3D4uGtW4yhzyKrn p7Mvm3qg==; Received: from [2001:4bb8:180:1ec3:c70:4a89:bc61:2] (helo=localhost) by bombadil.infradead.org with esmtpsa (Exim 4.92 #3 (Red Hat Linux)) id 1hxRBT-00066F-Ch; Tue, 13 Aug 2019 07:25:31 +0000 From: Christoph Hellwig To: Tony Luck , Fenghua Yu , Mike Travis , Dimitri Sivanich Cc: Arnd Bergmann , Greg Kroah-Hartman , linux-ia64@vger.kernel.org, linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 05/28] PCI/hotplug: remove the sgi_hotplug driver Date: Tue, 13 Aug 2019 09:24:51 +0200 Message-Id: <20190813072514.23299-6-hch@lst.de> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190813072514.23299-1-hch@lst.de> References: <20190813072514.23299-1-hch@lst.de> MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org. See http://www.infradead.org/rpr.html Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org The SGI SN2 support is about to be removed. Remove this driver that depends on the SN2 support. Signed-off-by: Christoph Hellwig --- drivers/pci/hotplug/Kconfig | 9 - drivers/pci/hotplug/Makefile | 1 - drivers/pci/hotplug/sgi_hotplug.c | 700 ------------------------------ 3 files changed, 710 deletions(-) delete mode 100644 drivers/pci/hotplug/sgi_hotplug.c diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index e9f78eb390d2..e7b493c22bf3 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -147,15 +147,6 @@ config HOTPLUG_PCI_RPA_DLPAR When in doubt, say N. -config HOTPLUG_PCI_SGI - tristate "SGI PCI Hotplug Support" - 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. - config HOTPLUG_PCI_S390 bool "System z PCI Hotplug Support" depends on S390 && 64BIT diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 7e3331603714..5196983220df 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o obj-$(CONFIG_HOTPLUG_PCI_POWERNV) += pnv-php.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 diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c deleted file mode 100644 index 231f5bdd3d2d..000000000000 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ /dev/null @@ -1,700 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../pci.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"); - - -/* 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 SN_SLOT_NAME_SIZE 33 /* size of name string */ - -/* internal list head */ -static struct list_head sn_hp_list; - -/* hotplug_slot struct's private pointer */ -struct slot { - int device_num; - struct pci_bus *pci_bus; - /* this struct for glue internal only */ - struct hotplug_slot hotplug_slot; - struct list_head hp_list; - char physical_path[SN_SLOT_NAME_SIZE]; -}; - -struct pcibr_slot_enable_resp { - int resp_sub_errno; - char resp_l1_msg[PCI_L1_QSIZE + 1]; -}; - -struct pcibr_slot_disable_resp { - int resp_sub_errno; - char resp_l1_msg[PCI_L1_QSIZE + 1]; -}; - -enum sn_pci_req_e { - PCI_REQ_SLOT_ELIGIBLE, - PCI_REQ_SLOT_DISABLE -}; - -static int enable_slot(struct hotplug_slot *slot); -static int disable_slot(struct hotplug_slot *slot); -static inline int get_power_status(struct hotplug_slot *slot, u8 *value); - -static const struct hotplug_slot_ops sn_hotplug_slot_ops = { - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .get_power_status = get_power_status, -}; - -static DEFINE_MUTEX(sn_hotplug_mutex); - -static struct slot *to_slot(struct hotplug_slot *bss_hotplug_slot) -{ - return container_of(bss_hotplug_slot, struct slot, hotplug_slot); -} - -static ssize_t path_show(struct pci_slot *pci_slot, char *buf) -{ - int retval = -ENOENT; - struct slot *slot = to_slot(pci_slot->hotplug); - - if (!slot) - return retval; - - retval = sprintf(buf, "%s\n", slot->physical_path); - return retval; -} - -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; - u16 busnum, segment, ioboard_type; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); - - /* Check to see if this is a valid slot on 'pci_bus' */ - if (!(pcibus_info->pbi_valid_devices & (1 << device))) - return -EPERM; - - 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 ((ioboard_type == L1_BRICKTYPE_IX || - ioboard_type == L1_BRICKTYPE_IA) && - (segment == 1 && busnum == 0 && device != 1)) - return -EPERM; - - return 1; -} - -static int sn_pci_bus_valid(struct pci_bus *pci_bus) -{ - struct pcibus_info *pcibus_info; - 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 */ - 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: - return -EPERM; - break; - } - - return -EIO; -} - -static int sn_hp_slot_private_alloc(struct hotplug_slot **bss_hotplug_slot, - struct pci_bus *pci_bus, int device, - char *name) -{ - struct pcibus_info *pcibus_info; - struct slot *slot; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - - slot->device_num = device; - slot->pci_bus = pci_bus; - sprintf(name, "%04x:%02x:%02x", - pci_domain_nr(pci_bus), - ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), - device + 1); - - sn_generate_path(pci_bus, slot->physical_path); - - list_add(&slot->hp_list, &sn_hp_list); - *bss_hotplug_slot = &slot->hotplug_slot; - - return 0; -} - -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(&slot->hp_list); - sysfs_remove_file(&pci_slot->kobj, - &sn_slot_path_attr.attr); - break; - } - return bss_hotplug_slot; -} - -static void sn_bus_free_data(struct pci_dev *dev) -{ - struct pci_bus *subordinate_bus; - struct pci_dev *child; - - /* Recursively clean up sn_irq_info structs */ - if (dev->subordinate) { - subordinate_bus = dev->subordinate; - 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, char **ssdt) -{ - struct slot *slot = to_slot(bss_hotplug_slot); - struct pcibus_info *pcibus_info; - struct pcibr_slot_enable_resp resp; - int rc; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); - - /* - * Power-on and initialize the slot in the SN - * PCI infrastructure. - */ - rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt); - - - if (rc == PCI_SLOT_ALREADY_UP) { - pci_dbg(slot->pci_bus->self, "is already active\n"); - return 1; /* return 1 to user */ - } - - if (rc == PCI_L1_ERR) { - pci_dbg(slot->pci_bus->self, "L1 failure %d with message: %s", - resp.resp_sub_errno, resp.resp_l1_msg); - return -EPERM; - } - - if (rc) { - pci_dbg(slot->pci_bus->self, "insert failed with error %d sub-error %d\n", - rc, resp.resp_sub_errno); - return -EIO; - } - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); - pcibus_info->pbi_enabled_devices |= (1 << device_num); - - return 0; -} - -static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, - int device_num, int action) -{ - struct slot *slot = to_slot(bss_hotplug_slot); - struct pcibus_info *pcibus_info; - struct pcibr_slot_disable_resp resp; - int rc; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); - - rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); - - if ((action == PCI_REQ_SLOT_ELIGIBLE) && - (rc == PCI_SLOT_ALREADY_DOWN)) { - pci_dbg(slot->pci_bus->self, "Slot %s already inactive\n", slot->physical_path); - return 1; /* return 1 to user */ - } - - if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) { - pci_dbg(slot->pci_bus->self, "Cannot remove last 33MHz card\n"); - return -EPERM; - } - - if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) { - pci_dbg(slot->pci_bus->self, "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) { - pci_dbg(slot->pci_bus->self, "remove failed with error %d sub-error %d\n", - rc, resp.resp_sub_errno); - return -EIO; - } - - if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc) - return 0; - - if ((action == PCI_REQ_SLOT_DISABLE) && !rc) { - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); - pcibus_info->pbi_enabled_devices &= ~(1 << device_num); - pci_dbg(slot->pci_bus->self, "remove successful\n"); - return 0; - } - - if ((action == PCI_REQ_SLOT_DISABLE) && rc) { - pci_dbg(slot->pci_bus->self, "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 = to_slot(bss_hotplug_slot); - struct pci_bus *new_bus = NULL; - struct pci_dev *dev; - 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 */ - mutex_lock(&sn_hotplug_mutex); - - /* - * Power-on and initialize the slot in the SN - * 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, &ssdt); - if (rc) { - 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) { - pci_dbg(slot->pci_bus->self, "no device in slot\n"); - mutex_unlock(&sn_hotplug_mutex); - return -ENODEV; - } - - /* - * Map SN resources for all functions on the card - * to the Linux PCI interface and tell the drivers - * about them. - */ - 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; - } - } - } - - /* - * 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)) { - pci_dbg(slot->pci_bus->self, "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); - - pci_unlock_rescan_remove(); - mutex_unlock(&sn_hotplug_mutex); - - if (rc == 0) - pci_dbg(slot->pci_bus->self, "insert operation successful\n"); - else - pci_dbg(slot->pci_bus->self, "insert operation failed rc = %d\n", rc); - - return rc; -} - -static int disable_slot(struct hotplug_slot *bss_hotplug_slot) -{ - struct slot *slot = to_slot(bss_hotplug_slot); - struct pci_dev *dev, *temp; - int rc; - acpi_handle ssdt_hdl = NULL; - - /* Acquire update access to the bus */ - mutex_lock(&sn_hotplug_mutex); - - /* is it okay to bring this slot down? */ - rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, - PCI_REQ_SLOT_ELIGIBLE); - 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 */ - ssdt_hdl = chandle; - - 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.*/ - 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_hdl) { - acpi_status ret; - ret = acpi_unload_parent_table(ssdt_hdl); - if (ACPI_FAILURE(ret)) { - acpi_handle_err(ssdt_hdl, - "%s: acpi_unload_parent_table failed (0x%x)\n", - __func__, ret); - /* try to continue on */ - } - } - - /* free the collected sysdata pointers */ - sn_bus_free_sysdata(); - - /* Deactivate slot */ - rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, - PCI_REQ_SLOT_DISABLE); - leaving: - /* Release the bus lock */ - mutex_unlock(&sn_hotplug_mutex); - - return rc; -} - -static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, - u8 *value) -{ - struct slot *slot = to_slot(bss_hotplug_slot); - struct pcibus_info *pcibus_info; - u32 power; - - pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); - 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(to_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; - - /* - * Currently only four devices are supported, - * in the future there maybe more -- up to 32. - */ - - for (device = 0; device < SN_MAX_HP_SLOTS ; device++) { - if (sn_pci_slot_valid(pci_bus, device) != 1) - continue; - - if (sn_hp_slot_private_alloc(&bss_hotplug_slot, - pci_bus, device, name)) { - rc = -ENOMEM; - goto alloc_err; - } - bss_hotplug_slot->ops = &sn_hotplug_slot_ops; - - rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name); - if (rc) - goto register_err; - - pci_slot = bss_hotplug_slot->pci_slot; - rc = sysfs_create_file(&pci_slot->kobj, - &sn_slot_path_attr.attr); - if (rc) - goto alloc_err; - } - pci_dbg(pci_bus->self, "Registered bus with hotplug\n"); - return rc; - -register_err: - pci_dbg(pci_bus->self, "bus failed to register with err = %d\n", - rc); - - /* destroy THIS element */ - sn_hp_destroy(); - sn_release_slot(bss_hotplug_slot); - -alloc_err: - /* destroy anything else on the list */ - while ((bss_hotplug_slot = sn_hp_destroy())) { - pci_hp_deregister(bss_hotplug_slot); - sn_release_slot(bss_hotplug_slot); - } - - return rc; -} - -static int __init sn_pci_hotplug_init(void) -{ - struct pci_bus *pci_bus = NULL; - int rc; - int registered = 0; - - if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) { - printk(KERN_ERR "%s: PROM version does not support hotplug.\n", - __func__); - return -EPERM; - } - - INIT_LIST_HEAD(&sn_hp_list); - - while ((pci_bus = pci_find_next_bus(pci_bus))) { - if (!pci_bus->sysdata) - continue; - - rc = sn_pci_bus_valid(pci_bus); - if (rc != 1) { - pci_dbg(pci_bus->self, "not a valid hotplug bus\n"); - continue; - } - pci_dbg(pci_bus->self, "valid hotplug bus\n"); - - rc = sn_hotplug_slot_register(pci_bus); - if (!rc) { - registered = 1; - } else { - registered = 0; - break; - } - } - - return registered == 1 ? 0 : -ENODEV; -} - -static void __exit sn_pci_hotplug_exit(void) -{ - struct hotplug_slot *bss_hotplug_slot; - - while ((bss_hotplug_slot = sn_hp_destroy())) { - pci_hp_deregister(bss_hotplug_slot); - sn_release_slot(bss_hotplug_slot); - } - - if (!list_empty(&sn_hp_list)) - printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); -} - -module_init(sn_pci_hotplug_init); -module_exit(sn_pci_hotplug_exit);