From: Prarit Bhargava <prarit@sgi.com>
To: linux-hotplug@vger.kernel.org
Subject: [PATCH/RFC]: SGI Altix Hotplug Driver
Date: Tue, 15 Mar 2005 20:20:53 +0000 [thread overview]
Message-ID: <423743A5.1020403@sgi.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 227 bytes --]
Colleages,
Attached are the code and changes to the existing codeset for a
functional SGI Altix Hotplug Driver.
The code has been tested on several different Altix machines and is
(obviously) ready for review.
Thanks,
P.
[-- Attachment #2: bkexport.diff --]
[-- Type: text/plain, Size: 28497 bytes --]
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2005/03/15 20:04:09-05:00 prarit@sgi.com
# Many files:
# SGI PCI Hotplug Driver changes
# sn_pci_hotplug_glue.c, sn_pci_hotplug_core.c, sn_pci_hotplug.h:
# new file
#
# drivers/pci/hotplug/sn_pci_hotplug_glue.c
# 2005/03/15 20:01:59-05:00 prarit@sgi.com +418 -0
# SGI PCI Hotplug Driver changes
#
# drivers/pci/hotplug/sn_pci_hotplug_glue.c
# 2005/03/15 20:01:59-05:00 prarit@sgi.com +0 -0
# BitKeeper file /home/linux-2.5-hotplug/drivers/pci/hotplug/sn_pci_hotplug_glue.c
#
# drivers/pci/hotplug/sn_pci_hotplug_core.c
# 2005/03/15 20:01:54-05:00 prarit@sgi.com +335 -0
# SGI PCI Hotplug Driver changes
#
# drivers/pci/hotplug/sn_pci_hotplug_core.c
# 2005/03/15 20:01:54-05:00 prarit@sgi.com +0 -0
# BitKeeper file /home/linux-2.5-hotplug/drivers/pci/hotplug/sn_pci_hotplug_core.c
#
# drivers/pci/hotplug/sn_pci_hotplug.h
# 2005/03/15 20:01:02-05:00 prarit@sgi.com +46 -0
#
# drivers/pci/hotplug/sn_pci_hotplug.h
# 2005/03/15 20:01:02-05:00 prarit@sgi.com +0 -0
# BitKeeper file /home/linux-2.5-hotplug/drivers/pci/hotplug/sn_pci_hotplug.h
#
# drivers/pci/hotplug/Makefile
# 2005/03/15 20:00:30-05:00 prarit@sgi.com +9 -0
# SGI PCI Hotplug Driver changes
#
# drivers/pci/hotplug/Kconfig
# 2005/03/15 20:00:11-05:00 prarit@sgi.com +1 -1
# SGI PCI Hotplug Driver changes
#
# arch/ia64/sn/pci/pcibr/pcibr_provider.c
# 2005/03/15 19:59:29-05:00 prarit@sgi.com +37 -0
# SGI PCI Hotplug Driver changes
#
# arch/ia64/sn/include/pci/pcibr_provider.h
# 2005/03/15 19:58:07-05:00 prarit@sgi.com +2 -0
# SGI PCI Hotplug Driver changes
#
# arch/ia64/kernel/iosapic.c
# 2005/03/15 19:56:44-05:00 prarit@sgi.com +1 -1
# SGI PCI Hotplug Driver changes
#
diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c 2005-03-15 20:09:33 -05:00
+++ b/arch/ia64/kernel/iosapic.c 2005-03-15 20:09:33 -05:00
@@ -83,8 +83,8 @@
#include <asm/delay.h>
#include <asm/hw_irq.h>
#include <asm/io.h>
-#include <asm/iosapic.h>
#include <asm/machvec.h>
+#include <asm/iosapic.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/system.h>
diff -Nru a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h
--- a/arch/ia64/sn/include/pci/pcibr_provider.h 2005-03-15 20:09:33 -05:00
+++ b/arch/ia64/sn/include/pci/pcibr_provider.h 2005-03-15 20:09:33 -05:00
@@ -146,4 +146,6 @@
extern int pcibr_ate_alloc(struct pcibus_info *, int);
extern void pcibr_ate_free(struct pcibus_info *, int);
extern void ate_write(struct pcibus_info *, int, int, uint64_t);
+extern int sal_pcibr_slot_enable(struct pcibus_info *, int, void *);
+extern int sal_pcibr_slot_disable(struct pcibus_info *, int, int, void *);
#endif
diff -Nru a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c 2005-03-15 20:09:33 -05:00
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c 2005-03-15 20:09:33 -05:00
@@ -19,6 +19,40 @@
#include <asm/sn/addrs.h>
+int
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+ {
+ struct ia64_sal_retval ret_stuff;
+ uint64_t busnum;
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ busnum = ((struct pcibus_info *)soft)->pbi_buscommon.bs_persist_busnum;
+ SAL_CALL_NOLOCK(ret_stuff,
+ (u64) SN_SAL_IOIF_SLOT_ENABLE,
+ (u64) busnum, (u64) device, (u64) resp, 0, 0, 0, 0);
+
+ return (int)ret_stuff.v0;
+}
+
+
+int
+sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action, void *resp)
+ {
+ struct ia64_sal_retval ret_stuff;
+ uint64_t busnum;
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ busnum = ((struct pcibus_info *)soft)->pbi_buscommon.bs_persist_busnum;
+ SAL_CALL_NOLOCK(ret_stuff,
+ (u64) SN_SAL_IOIF_SLOT_DISABLE,
+ (u64) busnum, (u64) device, (u64) action, (u64) resp, 0, 0, 0);
+
+ return (int)ret_stuff.v0;
+}
+
+
static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
{
struct ia64_sal_retval ret_stuff;
@@ -168,3 +202,6 @@
pcibr_force_interrupt(sn_irq_info);
}
}
+
+EXPORT_SYMBOL(sal_pcibr_slot_enable);
+EXPORT_SYMBOL(sal_pcibr_slot_disable);
diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
--- a/drivers/pci/hotplug/Kconfig 2005-03-15 20:09:33 -05:00
+++ b/drivers/pci/hotplug/Kconfig 2005-03-15 20:09:33 -05:00
@@ -187,7 +187,7 @@
config HOTPLUG_PCI_SGI
tristate "SGI PCI Hotplug Support"
- depends on HOTPLUG_PCI && IA64_SGI_SN2
+ depends on HOTPLUG_PCI && IA64_GENERIC
help
Say Y here if you have an SGI IA64 Altix system.
diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
--- a/drivers/pci/hotplug/Makefile 2005-03-15 20:09:33 -05:00
+++ b/drivers/pci/hotplug/Makefile 2005-03-15 20:09:33 -05:00
@@ -2,6 +2,8 @@
# Makefile for the Linux kernel pci hotplug controller drivers.
#
+CPPFLAGS +=-Iarch/ia64/sn/include/
+
obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
@@ -14,6 +16,7 @@
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
pci_hotplug-objs := pci_hotplug_core.o
@@ -72,3 +75,9 @@
shpchp-objs += shpchprm_nonacpi.o
endif
endif
+
+ifdef CONFIG_HOTPLUG_PCI_SGI
+sgi_hotplug-objs := sn_pci_hotplug_core.o \
+ sn_pci_hotplug_glue.o
+endif
+
diff -Nru a/drivers/pci/hotplug/sn_pci_hotplug.h b/drivers/pci/hotplug/sn_pci_hotplug.h
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/pci/hotplug/sn_pci_hotplug.h 2005-03-15 20:09:33 -05:00
@@ -0,0 +1,46 @@
+#ifndef SN_PCI_HOTPLUG_H
+#define SN_PCI_HOTPLUG_H
+
+typedef enum sn_glue_pci_req_e sn_glue_pci_req_t;
+
+enum sn_glue_pci_req_e {
+ PCI_REQ_SLOT_ELIGIBLE,
+ PCI_REQ_SLOT_DISABLE
+};
+
+
+/* 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;
+};
+
+/* init and exit functions for glue */
+int sn_glue_init(void);
+void sn_glue_exit (void);
+
+/* standard hotplug functions */
+extern int sn_glue_slot_disable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num, int action);
+extern int sn_glue_slot_enable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num);
+extern u8 sn_glue_power_status_get(struct hotplug_slot *bss_hotplug_slot);
+
+/* functions to determine hp'ability of slots and busses */
+extern int sn_glue_pci_bus_valid(struct pci_bus *pci_bus);
+extern int sn_glue_pci_slot_valid(struct pci_bus *pci_bus, int device);
+
+/* memory alllocation and free */
+extern int sn_glue_hp_slot_private_alloc(
+ struct hotplug_slot *bss_hotplug_slot,
+ struct pci_bus *pci_bus, int device);
+extern struct hotplug_slot * sn_glue_hp_destroy(void);
+extern void sn_glue_pci_unfixup_slot(struct pci_dev *dev);
+extern void sn_glue_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_glue_bus_alloc_irq_data(struct pci_dev *dev);
+extern void sn_glue_bus_free_irq_data(struct pci_dev *dev);
+#endif /* SN_PCI_HOTPLUG_H */
diff -Nru a/drivers/pci/hotplug/sn_pci_hotplug_core.c b/drivers/pci/hotplug/sn_pci_hotplug_core.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/pci/hotplug/sn_pci_hotplug_core.c 2005-03-15 20:09:33 -05:00
@@ -0,0 +1,335 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2004 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.
+ *
+ * Current maintainer: Prarit Bhargava
+ */
+
+#include <linux/types.h>
+#include <asm/sn/addrs.h>
+
+#include <asm/sn/module.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+#include "../pci.h"
+#include "pci_hotplug.h"
+
+#include "sn_pci_hotplug.h"
+
+#define DRIVER_AUTHORS "SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"
+#define DRIVER_DESC "SGI Altix Hot Plug PCI Controller Driver"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHORS);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+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 sn_hotplug_slot_ops = {
+ .owner = THIS_MODULE,
+ .enable_slot = enable_slot,
+ .disable_slot = disable_slot,
+ .set_attention_status = NULL,
+ .get_power_status = get_power_status,
+ .get_attention_status = NULL,
+ .get_latch_status = NULL,
+ .get_adapter_status = NULL,
+ .get_address = NULL,
+};
+
+static struct rw_semaphore sn_hotplug_lock;
+
+unsigned int __devinit pci_scan_child_bus(struct pci_bus *);
+
+/*
+ * enable_slot() - PCI hot-plug enable slot service routine. Called for
+ * an insert operation.
+ */
+static int
+enable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pci_dev_wrapped wrapped_dev;
+ struct pci_bus_wrapped wrapped_bus;
+ struct pci_bus *new_bus = NULL;
+ struct pci_dev *dev;
+ int func, num_funcs;
+ int new_ppb = 0;
+ int rc = 0;
+
+ /* Serialize the Linux PCI infrastructure */
+ down_write(&sn_hotplug_lock);
+
+ /*Power-on and initialize the slot in the SN
+ PCI infrastructure */
+ if ((rc = sn_glue_slot_enable(bss_hotplug_slot,
+ slot->device_num)) != 0)
+ return rc;
+
+ /* This call actually adds the device's functions to
+ Linux's knowledge. It does not traverse bridges in
+ effort to find devices below the bridge.*/
+ num_funcs = pci_scan_slot(slot->pci_bus,
+ PCI_DEVFN(slot->device_num+1, PCI_FUNC(0)));
+
+ if (!num_funcs) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "Could not find a device in this slot\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ up_write(&sn_hotplug_lock);
+ return(-ENODEV);
+ }
+
+ memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+ memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+
+ /* 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) {
+ wrapped_dev.dev = dev;
+ wrapped_bus.bus = dev->bus;
+
+ 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);
+
+ new_ppb = 1;
+ }
+
+ sn_glue_bus_alloc_irq_data(dev);
+
+ pci_dev_put(dev);
+
+ } /* if (dev) */
+ } /* for (func = 0; func < num_funcs; func++) */
+
+ /* 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);
+
+ /* Release the bus lock */
+ up_write(&sn_hotplug_lock);
+
+ if (rc == 0)
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "Insert operation successful\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ else
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "Insert operation failed, rc = %d\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, rc, bss_hotplug_slot->name);
+
+ return(rc);
+}
+
+
+
+/*
+ * disable_slot() - PCI hot-plug disable slot service routine.
+ * Called for a remove operation.
+ */
+static int
+disable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pci_dev *dev;
+ int func;
+ int rc = 0;
+
+ /* Acquire update access to the bus */
+ down_write(&sn_hotplug_lock);
+
+ /* is it okay to bring this slot down? */
+ if ((rc = sn_glue_slot_disable(bss_hotplug_slot, slot->device_num,
+ PCI_REQ_SLOT_ELIGIBLE)) != 0)
+ goto leaving;
+
+ /* 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) {
+ sn_glue_bus_free_irq_data(dev);
+ pci_remove_bus_device(dev);
+ }
+ }
+
+ rc = sn_glue_slot_disable(bss_hotplug_slot, slot->device_num,
+ PCI_REQ_SLOT_DISABLE);
+
+ /* Release the bus lock */
+leaving:
+ up_write(&sn_hotplug_lock);
+
+ return(rc);
+}
+
+
+/*
+ * get_power_status() - PCI hot-plug get slot power status service routine.
+ */
+static int
+get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value)
+{
+ down_read(&sn_hotplug_lock);
+ *value = sn_glue_power_status_get(bss_hotplug_slot);
+ up_read(&sn_hotplug_lock);
+
+ return(0);
+}
+
+/*
+ * sn_hotplug_slot_register() - register slots on a bus that support the PCI
+ * hot-plug feature with the PCI hotplug core
+ */
+int
+sn_hotplug_slot_register(struct pci_bus *pci_bus)
+{
+ int first_device, last_device;
+ int device;
+ struct hotplug_slot *bss_hotplug_slot;
+ int rc = 0;
+
+ if (sn_glue_pci_bus_valid(pci_bus))
+ {
+ printk("%s: not a valid hotplug bus\n", __FUNCTION__);
+ return 0;
+ }
+ printk("%s: valid hotplug bus\n", __FUNCTION__);
+
+ first_device = 0;
+ last_device = 1;
+
+ for (device = 0; device < 4; device++) {
+
+ if (sn_glue_pci_slot_valid(pci_bus, device))
+ continue;
+
+ bss_hotplug_slot = (struct hotplug_slot *)
+ kmalloc(sizeof(struct hotplug_slot),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot) {
+ rc = -ENOMEM;
+ continue;
+ }
+ memset(bss_hotplug_slot, 0, sizeof(struct hotplug_slot));
+
+ bss_hotplug_slot->info = (struct hotplug_slot_info *)
+ kmalloc(sizeof(struct hotplug_slot_info),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot->info) {
+ kfree(bss_hotplug_slot);
+ rc = -ENOMEM;
+ continue;
+ }
+ memset(bss_hotplug_slot->info, 0,
+ sizeof(struct hotplug_slot_info));
+
+ if (sn_glue_hp_slot_private_alloc(bss_hotplug_slot,
+ pci_bus, device))
+ {
+ kfree(bss_hotplug_slot->info);
+ kfree(bss_hotplug_slot);
+ rc = -ENOMEM;
+ continue;
+ }
+
+ bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
+
+ pci_hp_register(bss_hotplug_slot);
+
+ } /*for (device = 0; device < 4; device++)*/
+
+ return(rc);
+}
+
+/* sn_hotplug_slot_deregister - deregister pci_bus from hotplug subsystem */
+void
+sn_hotplug_slot_deregister(struct hotplug_slot *bss_hotplug_slot)
+{
+ pci_hp_deregister(bss_hotplug_slot);
+
+ if (bss_hotplug_slot->info)
+ kfree(bss_hotplug_slot->info);
+
+ kfree(bss_hotplug_slot);
+}
+
+static int
+sn_pci_hotplug_init(void)
+{
+ struct list_head *ln;
+ struct pci_bus *pci_bus;
+
+ init_rwsem(&sn_hotplug_lock);
+
+ if (sn_glue_init())
+ {
+ printk(KERN_ERR "%s: internal data structures init fail\n",
+ __FILE__);
+ return -1;
+ }
+
+ for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+
+ pci_bus = pci_bus_b(ln);
+ if (!pci_bus->sysdata)
+ continue;
+
+ sn_hotplug_slot_register(pci_bus);
+ }
+
+ return 0;
+}
+
+static void sn_pci_hotplug_exit(void)
+{
+ struct hotplug_slot *bss_hotplug_slot = NULL;
+
+ while ((bss_hotplug_slot = sn_glue_hp_destroy()))
+ {
+ pci_hp_deregister(bss_hotplug_slot);
+ bss_hotplug_slot = NULL;
+ }
+
+ sn_glue_exit();
+}
+
+module_init(sn_pci_hotplug_init);
+module_exit(sn_pci_hotplug_exit);
+
diff -Nru a/drivers/pci/hotplug/sn_pci_hotplug_glue.c b/drivers/pci/hotplug/sn_pci_hotplug_glue.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/pci/hotplug/sn_pci_hotplug_glue.c 2005-03-15 20:09:33 -05:00
@@ -0,0 +1,418 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <asm/sn/types.h>
+#include <asm/sn/addrs.h>
+
+#include "pci/pcidev.h"
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcibr_provider.h"
+
+#include <asm/sn/l1.h>
+#include <asm/sn/module.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+
+#include "../pci.h"
+#include "pci_hotplug.h"
+
+#include "sn_pci_hotplug.h"
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
+
+#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 PCI_L1_QSIZE 128 /* our L1 message buffer size */
+
+/* internal list head */
+struct list_head sn_glue_hp_list;
+
+/* The list of SN hotplug_slots. The list is maintained
+ within the private pointer */
+
+struct pcibr_slot_enable_resp_s {
+ int resp_sub_errno;
+ char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+struct pcibr_slot_disable_resp_s {
+ int resp_sub_errno;
+ char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+/*from arch/ia64/sn/kernel/io_init.c: */
+extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_pci_unfixup_slot(struct pci_dev *dev);
+
+int
+sn_glue_pci_slot_valid(struct pci_bus *pci_bus, int device)
+{
+ struct pcibus_info *pcibus_info;
+ int bricktype;
+ int bus_num;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(pci_bus);
+
+ /* Check to see if this is a valid slot on 'pci_bus' */
+ 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;
+
+ /* Do not allow hotplug operations on base I/O cards */
+ if ((bricktype == L1_BRICKTYPE_IX ||
+ bricktype == L1_BRICKTYPE_IA) &&
+ (bus_num == 1 && device != 1))
+ return -EPERM;
+ return 0;
+}
+
+int
+sn_glue_pci_bus_valid(struct pci_bus *pci_bus)
+{
+ struct pcibus_info *pcibus_info;
+ int asic_type;
+ int bricktype;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(pci_bus);
+
+ /* Don't register slots hanging off the TIOCA bus */
+ asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
+ if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
+ return -1;
+
+ bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid);
+
+ /* Only register slots in I/O Bricks that support hotplug */
+ switch (bricktype) {
+ case L1_BRICKTYPE_IX:
+ case L1_BRICKTYPE_PX:
+ case L1_BRICKTYPE_IA:
+ case L1_BRICKTYPE_PA:
+ return 0;
+ break;
+ default:
+ return -EPERM;
+ break;
+ }
+
+ return -EIO;
+}
+
+int
+sn_glue_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, struct pci_bus *pci_bus, int device)
+{
+ struct pcibus_info *pcibus_info;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(pci_bus);
+
+ bss_hotplug_slot->private = (struct slot *)
+ kmalloc(sizeof(struct slot),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot->private) {
+ return -ENOMEM;
+ }
+ memset(bss_hotplug_slot->private, 0, sizeof(struct slot));
+
+ bss_hotplug_slot->name = (char *) kmalloc (33, GFP_KERNEL);
+ if (!bss_hotplug_slot->name) {
+ kfree(bss_hotplug_slot->private);
+ return -ENOMEM;
+ }
+
+ ((struct slot *)bss_hotplug_slot->private)->device_num = device;
+ ((struct slot *)bss_hotplug_slot->private)->pci_bus = pci_bus;
+
+ sprintf(bss_hotplug_slot->name, "m_%c%c%c%c%.2d_b_%d_s_%d",
+ '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),
+ ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, device + 1);
+
+printk("%s: adding %s [%p]\n", __FUNCTION__, bss_hotplug_slot->name, bss_hotplug_slot);
+ ((struct slot *)bss_hotplug_slot->private)->hotplug_slot =
+ bss_hotplug_slot;
+ list_add(&((struct slot *)bss_hotplug_slot->private)->hp_list,
+ &sn_glue_hp_list);
+
+ return 0;
+}
+
+void
+sn_glue_hp_slot_private_free(struct hotplug_slot *bss_hotplug_slot)
+{
+ if (bss_hotplug_slot->name)
+ kfree(bss_hotplug_slot->name);
+
+ if (bss_hotplug_slot->private)
+ kfree(bss_hotplug_slot->private);
+}
+
+struct hotplug_slot * sn_glue_hp_destroy(void)
+{
+ struct slot *slot;
+ struct list_head *list;
+ struct list_head *next;
+ struct hotplug_slot *bss_hotplug_slot = NULL;
+
+ list_for_each_safe( list, next, &sn_glue_hp_list)
+ {
+ slot = list_entry(list, struct slot, hp_list);
+
+ bss_hotplug_slot = slot->hotplug_slot;
+ printk("%s: cleaning %s [%p]\n", __FUNCTION__, bss_hotplug_slot->name, bss_hotplug_slot);
+ sn_glue_hp_slot_private_free(bss_hotplug_slot);
+ list_del(&((struct slot *)bss_hotplug_slot->private)->hp_list);
+ break;
+ }
+
+ return bss_hotplug_slot;
+}
+
+/* This function recursively sets up the sn_irq_info structs */
+void sn_glue_bus_alloc_irq_data(struct pci_dev *dev)
+{
+ struct list_head *node = NULL;
+ struct pci_bus *subordinate_bus = NULL;
+ struct pci_dev *child = NULL;
+
+ if (dev->subordinate) {
+ subordinate_bus = dev->subordinate;
+ list_for_each(node, &subordinate_bus->devices) {
+ child = list_entry(node, struct pci_dev, bus_list);
+ sn_glue_bus_free_irq_data(child);
+ }
+ }
+
+ /* Increment the dev reference count so pci_remove_bus_device() does
+ not free the pci_dev structure; it is needed by unfixup. */
+ pci_dev_get(dev);
+
+ sn_glue_pci_fixup_slot(dev);
+}
+
+/* This function recursively cleans up sn_irq_info structs */
+void sn_glue_bus_free_irq_data(struct pci_dev *dev)
+{
+ struct list_head *node = NULL;
+ struct pci_bus *subordinate_bus = NULL;
+ struct pci_dev *child = NULL;
+
+ if (dev->subordinate) {
+ subordinate_bus = dev->subordinate;
+ list_for_each(node, &subordinate_bus->devices) {
+ child = list_entry(node, struct pci_dev, bus_list);
+ sn_glue_bus_free_irq_data(child);
+ }
+ }
+
+ /* Decrement dev reference count so pci_dev structure is freed */
+ pci_dev_put(dev);
+
+ sn_glue_pci_unfixup_slot(dev);
+}
+
+u8
+sn_glue_power_status_get(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ u8 retval;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(slot->pci_bus);
+ retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
+
+ return retval;
+}
+
+void
+sn_glue_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot, int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(slot->pci_bus);
+ pcibus_info->pbi_enabled_devices |= (1 << device_num);
+}
+
+void
+sn_glue_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot, int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(slot->pci_bus);
+ pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
+}
+
+int
+sn_glue_slot_enable(struct hotplug_slot *bss_hotplug_slot, int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ struct pcibr_slot_enable_resp_s resp;
+ int rc = 0;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(slot->pci_bus);
+
+
+ /*Power-on and initialize the slot in the SN
+ PCI infrastructure */
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+
+ if (rc == PCI_SLOT_ALREADY_UP) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug insert failed because the slot is\n"
+ "already powered-up and active\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ return(0);
+ }
+
+ if (rc == PCI_L1_ERR) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug insert failed because of L1 hardware\n"
+ "controller error %d; the L1 message is:\n%s\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, resp.resp_sub_errno,
+ resp.resp_l1_msg, bss_hotplug_slot->name);
+ return(-EPERM);
+ }
+
+ if (rc) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug insert failed with error %d and "
+ "sub-error %d\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, rc,
+ resp.resp_sub_errno, bss_hotplug_slot->name);
+ return(-EIO);
+ }
+
+ sn_glue_slot_mark_enable(bss_hotplug_slot, device_num);
+
+ return 0;
+}
+
+int
+sn_glue_slot_disable(struct hotplug_slot *bss_hotplug_slot, int device_num, int action)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ struct pcibr_slot_disable_resp_s resp;
+ int rc;
+
+ pcibus_info = (struct pcibus_info *)SN_PCIBUS_BUSSOFT(slot->pci_bus);
+
+ /* is it okay to bring this slot down? */
+ rc = sal_pcibr_slot_disable(pcibus_info, device_num,
+ action, &resp);
+
+
+ if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_SLOT_ALREADY_DOWN)) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug remove failed because the slot is\n"
+ "already powered-down and inactive\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ return(-ENODEV);
+ }
+
+ if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug remove failed because the last card\n"
+ "cannot be removed from a bus running at 33MHz\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ return -EPERM;
+ }
+
+ if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug remove failed because of L1 hardware\n"
+ "controller error %d; the L1 message is:\n%s\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, resp.resp_sub_errno,
+ resp.resp_l1_msg, bss_hotplug_slot->name);
+ return -EPERM;
+ }
+
+ if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc)) {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "PCI hot-plug remove failed with error %d and "
+ "sub-error %d\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, rc,
+ resp.resp_sub_errno, bss_hotplug_slot->name);
+ return(-EIO);
+ }
+
+ if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc)) {
+ return 0;
+ }
+
+ if ((action == PCI_REQ_SLOT_DISABLE) && (rc == 0))
+ {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "Remove operation successful\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, bss_hotplug_slot->name);
+ sn_glue_slot_mark_disable(bss_hotplug_slot, device_num);
+ return rc;
+ }
+
+ if ((action == PCI_REQ_SLOT_DISABLE) && (rc))
+ {
+ printk("Begin PCI Hot-Plug Message for -> %s\n"
+ "Remove operation failed, rc = %d\n"
+ "End PCI Hot-Plug Message for -> %s\n",
+ bss_hotplug_slot->name, rc, bss_hotplug_slot->name);
+ return rc;
+ }
+
+ return rc;
+}
+
+void
+sn_glue_pci_unfixup_slot(struct pci_dev *dev)
+{
+ sn_pci_unfixup_slot(dev);
+}
+
+void
+sn_glue_pci_fixup_slot(struct pci_dev *dev)
+{
+ sn_pci_fixup_slot(dev);
+}
+
+
+
+int
+sn_glue_init(void)
+{
+ INIT_LIST_HEAD(&sn_glue_hp_list);
+
+ return 0;
+}
+
+void
+sn_glue_exit(void)
+{
+ if (!list_empty(&sn_glue_hp_list))
+ printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
+}
next reply other threads:[~2005-03-15 20:20 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-15 20:20 Prarit Bhargava [this message]
2005-03-16 4:34 ` [PATCH/RFC]: SGI Altix Hotplug Driver Randy.Dunlap
2005-03-16 12:36 ` Prarit Bhargava
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=423743A5.1020403@sgi.com \
--to=prarit@sgi.com \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.