Skip to contentSkip to conversation

: SN Hotplug Driver - SN Hotplug Driver code

PATCH New Prarit Bhargava 1 participant 1 message May 2, 2005 PCI

lore
Share & tools
lore
#0 lore raw

PATCH 5/6 : SN Hotplug Driver - SN Hotplug Driver code

This patch is the SGI hotplug driver and additional changes required for the driver. These modifications include changes to the SN io_init.c code for memory management, the inclusion of new SAL calls to enable and disable PCI slots, and a hotplug-style driver.

 arch/ia64/sn/kernel/io_init.c           |  139 ++++---
 arch/ia64/sn/kernel/irq.c               |    6 
 arch/ia64/sn/pci/pcibr/pcibr_provider.c |   37 +
 drivers/pci/hotplug/Kconfig             |    5 
 drivers/pci/hotplug/Makefile            |    1 
 drivers/pci/hotplug/sgi_hotplug.c       |  611 ++++++++++++++++++++++++++++++++
 include/asm-ia64/sn/pcidev.h            |    4 
 7 files changed, 749 insertions(+), 54 deletions(-)
arch/ia64/sn/kernel/io_init.c +90 -49
diff -urNp sn_version/arch/ia64/sn/kernel/io_init.c hp/arch/ia64/sn/kernel/io_init.c
@@ -23,6 +23,14 @@
 
 nasid_t master_nasid = INVALID_NASID;	/* Partition Master */
 
+static struct list_head sn_sysdata_list;
+
+/* sysdata list struct */
+struct sysdata_el {
+	struct list_head entry;
+	void *sysdata;
+};
+
 struct slab_info {
 	struct hubdev_info hubdev;
 };
@@ -106,23 +114,6 @@ sal_get_pcidev_info(u64 segment, u64 bus
 }
 
 /*
- * sn_alloc_pci_sysdata() - This routine allocates a pci controller
- *	which is expected as the pci_dev and pci_bus sysdata by the Linux
- *	PCI infrastructure.
- */
-static inline struct pci_controller *sn_alloc_pci_sysdata(void)
-{
-	struct pci_controller *pci_sysdata;
-
-	pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
-	if (!pci_sysdata)
-		BUG();
-
-	memset(pci_sysdata, 0, sizeof(*pci_sysdata));
-	return pci_sysdata;
-}
-
-/*
  * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
  *	each node in the system.
  */
@@ -187,6 +178,15 @@ static void sn_fixup_ionodes(void)
 
 }
 
+void sn_pci_unfixup_slot(struct pci_dev *dev)
+{
+	struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
+
+	sn_irq_unfixup(dev);
+	pci_dev_put(host_pci_dev);
+	pci_dev_put(dev);
+}
+
 /*
  * sn_pci_fixup_slot() - This routine sets up a slot's resources
  * consistent with the Linux PCI abstraction layer.  Resources acquired
@@ -197,21 +197,22 @@ void sn_pci_fixup_slot(struct pci_dev *d
 {
 	int idx;
 	int segment = 0;
-	int status = 0;
+	uint64_t size;
+	struct sn_irq_info *sn_irq_info;
 	struct pci_bus *host_pci_bus;
 	struct pci_dev *host_pci_dev;
-	struct sn_irq_info *sn_irq_info;
-	unsigned long size;
+	int status = 0;
 	unsigned int bus_no, devfn;
 
+	pci_dev_get(dev); /* for the sysdata pointer */
 	dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
 	if (SN_PCIDEV_INFO(dev) <= 0)
-		BUG();		/* Cannot afford to run out of memory */
+		BUG(); /* Cannot afford to run out of memory */
 	memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));
 
 	sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
 	if (sn_irq_info <= 0)
-		BUG();		/* Cannot afford to run out of memory */
+		BUG(); /* Cannot afford to run out of memory */
 	memset(sn_irq_info, 0, sizeof(struct sn_irq_info));
 
 	/* Call to retrieve pci device information needed by kernel. */
@@ -242,10 +243,10 @@ void sn_pci_fixup_slot(struct pci_dev *d
 			dev->resource[idx].parent = &iomem_resource;
 	}
 
-	/* Using the PROMs values for the PCI host bus, get the Linux
+	/*
+	 * Using the PROMs values for the PCI host bus, get the Linux
 	 * PCI host_pci_dev struct and set up host bus linkages
 	 */
-
 	bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
 	devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
 	host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
@@ -272,32 +273,35 @@ void sn_pci_fixup_slot(struct pci_dev *d
  * sn_pci_controller_fixup() - This routine sets up a bus's resources
  * consistent with the Linux PCI abstraction layer.
  */
-static void sn_pci_controller_fixup(int segment, int busnum)
+void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
 {
 	int status = 0;
 	int nasid, cnode;
-	struct pci_bus *bus;
 	struct pci_controller *controller;
 	struct pcibus_bussoft *prom_bussoft_ptr;
 	struct hubdev_info *hubdev_info;
 	void *provider_soft;
 
-	status =
-	    sal_get_pcibus_info((u64) segment, (u64) busnum,
-				(u64) ia64_tpa(&prom_bussoft_ptr));
-	if (status > 0) {
+	status = sal_get_pcibus_info((u64) segment, (u64) busnum,
+				     (u64) ia64_tpa(&prom_bussoft_ptr));
+	if (status > 0)
 		return;		/* bus # does not exist */
-	}
-
 	prom_bussoft_ptr = __va(prom_bussoft_ptr);
-	controller = sn_alloc_pci_sysdata();
-	/* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
 
-	bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+	controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+	if (!controller)
+		BUG();
+
 	if (bus == NULL) {
-		return;		/* error, or bus already scanned */
+		bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+		if (bus == NULL)
+			return;	/* error, or bus already scanned */
+		bus->sysdata = NULL;
 	}
 
+	if (bus->sysdata)
+		goto error_return; /* sysdata already alloc'd */
+
 	/*
 	 * Per-provider fixup.  Copies the contents from prom to local
 	 * area and links SN_PCIBUS_BUSSOFT().
@@ -305,15 +309,12 @@ static void sn_pci_controller_fixup(int 
 	 * Note:  Provider is responsible for ensuring that prom_bussoft_ptr
 	 * represents an asic-type that it can handle.
 	 */
-
-	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) {
-		return;		/* no further fixup necessary */
-	}
+	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
+		goto error_return; /* no further fixup necessary */
 
 	provider_soft = pcibr_bus_fixup(prom_bussoft_ptr);
-	if (provider_soft == NULL) {
-		return;		/* fixup failed or not applicable */
-	}
+	if (provider_soft == NULL)
+		goto error_return; /* fixup failed or not applicable */
 
 	/*
 	 * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
@@ -322,12 +323,47 @@ static void sn_pci_controller_fixup(int 
 
 	bus->sysdata = controller;
 	PCI_CONTROLLER(bus)->platform_data = provider_soft;
-
 	nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
 	cnode = nasid_to_cnodeid(nasid);
 	hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
 	SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
 	    &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
+
+	return;
+
+error_return:
+
+	kfree(controller);
+	return;
+}
+
+void sn_bus_store_sysdata(struct pci_dev *dev)
+{
+	struct sysdata_el *element;
+
+	element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+	if (!element) {
+		dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
+		return;
+	}
+	element->sysdata = dev->sysdata;
+	list_add(&element->entry, &sn_sysdata_list);
+}
+
+void sn_bus_free_sysdata(void)
+{
+	struct sysdata_el *element;
+	struct list_head *list;
+
+sn_sysdata_free_start:
+	list_for_each(list, &sn_sysdata_list) {
+		element = list_entry(list, struct sysdata_el, entry);
+		list_del(&element->entry);
+		kfree(element->sysdata);
+		kfree(element);
+		goto sn_sysdata_free_start;
+	}
+	return;
 }
 
 /*
@@ -354,15 +390,16 @@ static int __init sn_pci_init(void)
 	ia64_max_iommu_merge_mask = ~PAGE_MASK;
 	sn_fixup_ionodes();
 	sn_irq_lh_init();
+	INIT_LIST_HEAD(&sn_sysdata_list);
 	sn_init_cpei_timer();
 
 #ifdef CONFIG_PROC_FS
 	register_sn_procfs();
 #endif
 
-	for (i = 0; i < PCI_BUSES_TO_SCAN; i++) {
-		sn_pci_controller_fixup(0, i);
-	}
+	/* busses are not known yet ... */
+	for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+		sn_pci_controller_fixup(0, i, NULL);
 
 	/*
 	 * Generic Linux PCI Layer has created the pci_bus and pci_dev 
@@ -371,9 +408,8 @@ static int __init sn_pci_init(void)
 	 */
 
 	while ((pci_dev =
-		pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+		pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
 		sn_pci_fixup_slot(pci_dev);
-	}
 
 	sn_ioif_inited = 1;	/* sn I/O infrastructure now initialized */
 
@@ -415,3 +451,8 @@ cnodeid_get_geoid(cnodeid_t cnode)
 }
 
 subsys_initcall(sn_pci_init);
+EXPORT_SYMBOL(sn_pci_fixup_slot);
+EXPORT_SYMBOL(sn_pci_unfixup_slot);
+EXPORT_SYMBOL(sn_pci_controller_fixup);
+EXPORT_SYMBOL(sn_bus_store_sysdata);
+EXPORT_SYMBOL(sn_bus_free_sysdata);
arch/ia64/sn/kernel/irq.c +3 -3
diff -urNp sn_version/arch/ia64/sn/kernel/irq.c hp/arch/ia64/sn/kernel/irq.c
@@ -296,7 +296,6 @@ void sn_irq_fixup(struct pci_dev *pci_de
 	int cpu = nasid_slice_to_cpuid(nasid, slice);
 
 	pci_dev_get(pci_dev);
-
 	sn_irq_info->irq_cpuid = cpu;
 	sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
 
@@ -317,15 +316,16 @@ void sn_irq_unfixup(struct pci_dev *pci_
 		return;
 
 	sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info;
-	if (!sn_irq_info || !sn_irq_info->irq_irq)
+	if (!sn_irq_info || !sn_irq_info->irq_irq) {
+		kfree(sn_irq_info);
 		return;
+	}
 
 	unregister_intr_pda(sn_irq_info);
 	spin_lock(&sn_irq_info_lock);
 	list_del_rcu(&sn_irq_info->list);
 	spin_unlock(&sn_irq_info_lock);
 	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
-
 	pci_dev_put(pci_dev);
 }
 
arch/ia64/sn/pci/pcibr/pcibr_provider.c +37 -0
diff -urNp sn_version/arch/ia64/sn/pci/pcibr/pcibr_provider.c hp/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -19,6 +19,40 @@
 #include "xtalk/xwidgetdev.h"
 #include "xtalk/hubdev.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 = 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 = 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 @@ void pcibr_change_devices_irq(struct sn_
 		pcibr_force_interrupt(sn_irq_info);
 	}
 }
+
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);
drivers/pci/hotplug/Kconfig +3 -2
diff -urNp sn_version/drivers/pci/hotplug/Kconfig hp/drivers/pci/hotplug/Kconfig
@@ -187,9 +187,10 @@ config HOTPLUG_PCI_RPA_DLPAR
 
 config HOTPLUG_PCI_SGI
 	tristate "SGI PCI Hotplug Support"
-	depends on HOTPLUG_PCI && IA64_SGI_SN2
+	depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC)
 	help
-	  Say Y here if you have an SGI IA64 Altix system.
+	  Say Y here if you want to use the SGI Altix Hotplug
+	  Driver for PCI devices.
 
 	  When in doubt, say N.
 
drivers/pci/hotplug/Makefile +1 -0
diff -urNp sn_version/drivers/pci/hotplug/Makefile hp/drivers/pci/hotplug/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HOTPLUG_PCI_PCIE)		+= pcieh
 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
 
drivers/pci/hotplug/sgi_hotplug.c +611 -0

611 lines not on this page · raw message

include/asm-ia64/sn/pcidev.h +4 -0
diff -urNp sn_version/include/asm-ia64/sn/pcidev.h hp/include/asm-ia64/sn/pcidev.h
@@ -56,4 +56,8 @@ extern void sn_irq_unfixup(struct pci_de
 extern void sn_irq_lh_init(void);
 extern void sn_pci_fixup_slot(struct pci_dev *dev);
 extern void sn_pci_unfixup_slot(struct pci_dev *dev);
+extern void sn_pci_controller_fixup(int segment, int busnum,
+				    struct pci_bus *bus);
+extern void sn_bus_store_sysdata(struct pci_dev *dev);
+extern void sn_bus_free_sysdata(void);
 #endif				/* _ASM_IA64_SN_PCI_PCIDEV_H */