: SN Hotplug Driver - SN Hotplug Driver code
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.
Signed-off-by Prarit Bhargava <[email protected]>
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
@@ -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
@@ -296,7 +296,6 @@ void sn_irq_fixup(struct pci_dev *pci_deint 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
@@ -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
@@ -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
@@ -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
@@ -56,4 +56,8 @@ extern void sn_irq_unfixup(struct pci_deextern 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 */