* [PATCH/RFC]: SGI Altix Hotplug Driver
@ 2005-03-15 20:20 Prarit Bhargava
2005-03-16 4:34 ` Randy.Dunlap
2005-03-16 12:36 ` Prarit Bhargava
0 siblings, 2 replies; 3+ messages in thread
From: Prarit Bhargava @ 2005-03-15 20:20 UTC (permalink / raw)
To: linux-hotplug
[-- 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__);
+}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH/RFC]: SGI Altix Hotplug Driver
2005-03-15 20:20 [PATCH/RFC]: SGI Altix Hotplug Driver Prarit Bhargava
@ 2005-03-16 4:34 ` Randy.Dunlap
2005-03-16 12:36 ` Prarit Bhargava
1 sibling, 0 replies; 3+ messages in thread
From: Randy.Dunlap @ 2005-03-16 4:34 UTC (permalink / raw)
To: linux-hotplug
Prarit Bhargava wrote:
> 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.
Should send to pcihpd-discuss@lists.sourceforge.net
(for PCI hotplug drivers).
--
~Randy
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id\x14396&op=click
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH/RFC]: SGI Altix Hotplug Driver
2005-03-15 20:20 [PATCH/RFC]: SGI Altix Hotplug Driver Prarit Bhargava
2005-03-16 4:34 ` Randy.Dunlap
@ 2005-03-16 12:36 ` Prarit Bhargava
1 sibling, 0 replies; 3+ messages in thread
From: Prarit Bhargava @ 2005-03-16 12:36 UTC (permalink / raw)
To: linux-hotplug
Will do. I keep getting the lists mixed up :)
P.
Randy.Dunlap wrote:
> Prarit Bhargava wrote:
>
>> 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.
>
>
> Should send to pcihpd-discuss@lists.sourceforge.net
> (for PCI hotplug drivers).
>
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id\x14396&op=click
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-03-16 12:36 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-15 20:20 [PATCH/RFC]: SGI Altix Hotplug Driver Prarit Bhargava
2005-03-16 4:34 ` Randy.Dunlap
2005-03-16 12:36 ` Prarit Bhargava
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).