Commit cb4cb2cb authored by Prarit Bhargava's avatar Prarit Bhargava Committed by Tony Luck

[IA64] hotplug/ia64: SN Hotplug Driver: SN IRQ Fixes

This patch  fixes the SN IRQ code such that cpu affinity and
Hotplug can modify IRQ values.  The sn_irq_info structures are now locked
using a RCU lock mechanism to avoid lock contention in the lost interrupt
WAR code.
Signed-off-by: default avatarPrarit Bhargava <prarit@sgi.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent bd53d127
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <asm/sn/simulator.h> #include <asm/sn/simulator.h>
#include <asm/sn/tioca_provider.h> #include <asm/sn/tioca_provider.h>
char master_baseio_wid;
nasid_t master_nasid = INVALID_NASID; /* Partition Master */ nasid_t master_nasid = INVALID_NASID; /* Partition Master */
struct slab_info { struct slab_info {
...@@ -231,11 +230,13 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -231,11 +230,13 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
{ {
int idx; int idx;
int segment = 0; int segment = 0;
uint64_t size;
struct sn_irq_info *sn_irq_info;
struct pci_dev *host_pci_dev;
int status = 0; int status = 0;
struct pcibus_bussoft *bs; struct pcibus_bussoft *bs;
struct pci_bus *host_pci_bus;
struct pci_dev *host_pci_dev;
struct sn_irq_info *sn_irq_info;
unsigned long size;
unsigned int bus_no, devfn;
dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
if (SN_PCIDEV_INFO(dev) <= 0) if (SN_PCIDEV_INFO(dev) <= 0)
...@@ -253,7 +254,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -253,7 +254,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
(u64) __pa(SN_PCIDEV_INFO(dev)), (u64) __pa(SN_PCIDEV_INFO(dev)),
(u64) __pa(sn_irq_info)); (u64) __pa(sn_irq_info));
if (status) if (status)
BUG(); /* Cannot get platform pci device information information */ BUG(); /* Cannot get platform pci device information */
/* Copy over PIO Mapped Addresses */ /* Copy over PIO Mapped Addresses */
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
...@@ -275,15 +276,20 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -275,15 +276,20 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
dev->resource[idx].parent = &iomem_resource; dev->resource[idx].parent = &iomem_resource;
} }
/* set up host bus linkages */ /* Using the PROMs values for the PCI host bus, get the Linux
bs = SN_PCIBUS_BUSSOFT(dev->bus); * PCI host_pci_dev struct and set up host bus linkages
host_pci_dev = */
pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
SN_PCIDEV_INFO(dev)-> bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
pdi_slot_host_handle & 0xffffffff); devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
host_pci_dev = pci_get_slot(host_pci_bus, devfn);
SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
SN_PCIDEV_INFO(host_pci_dev); SN_PCIDEV_INFO(host_pci_dev);
SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
bs = SN_PCIBUS_BUSSOFT(dev->bus);
SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
...@@ -297,6 +303,9 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -297,6 +303,9 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
sn_irq_fixup(dev, sn_irq_info); sn_irq_fixup(dev, sn_irq_info);
} else {
SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
kfree(sn_irq_info);
} }
} }
...@@ -403,11 +412,7 @@ static int __init sn_pci_init(void) ...@@ -403,11 +412,7 @@ static int __init sn_pci_init(void)
*/ */
ia64_max_iommu_merge_mask = ~PAGE_MASK; ia64_max_iommu_merge_mask = ~PAGE_MASK;
sn_fixup_ionodes(); sn_fixup_ionodes();
sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL); sn_irq_lh_init();
if (sn_irq <= 0)
BUG(); /* Canno afford to run out of memory. */
memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS);
sn_init_cpei_timer(); sn_init_cpei_timer();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
This diff is collapsed.
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#ifndef _ASM_IA64_SN_INTR_H #ifndef _ASM_IA64_SN_INTR_H
#define _ASM_IA64_SN_INTR_H #define _ASM_IA64_SN_INTR_H
#include <linux/rcupdate.h>
#define SGI_UART_VECTOR (0xe9) #define SGI_UART_VECTOR (0xe9)
#define SGI_PCIBR_ERROR (0x33) #define SGI_PCIBR_ERROR (0x33)
...@@ -33,7 +35,7 @@ ...@@ -33,7 +35,7 @@
// The SN PROM irq struct // The SN PROM irq struct
struct sn_irq_info { struct sn_irq_info {
struct sn_irq_info *irq_next; /* sharing irq list */ struct sn_irq_info *irq_next; /* deprecated DO NOT USE */
short irq_nasid; /* Nasid IRQ is assigned to */ short irq_nasid; /* Nasid IRQ is assigned to */
int irq_slice; /* slice IRQ is assigned to */ int irq_slice; /* slice IRQ is assigned to */
int irq_cpuid; /* kernel logical cpuid */ int irq_cpuid; /* kernel logical cpuid */
...@@ -47,6 +49,8 @@ struct sn_irq_info { ...@@ -47,6 +49,8 @@ struct sn_irq_info {
int irq_cookie; /* unique cookie */ int irq_cookie; /* unique cookie */
int irq_flags; /* flags */ int irq_flags; /* flags */
int irq_share_cnt; /* num devices sharing IRQ */ int irq_share_cnt; /* num devices sharing IRQ */
struct list_head list; /* list of sn_irq_info structs */
struct rcu_head rcu; /* rcu callback list */
}; };
extern void sn_send_IPI_phys(int, long, int, int); extern void sn_send_IPI_phys(int, long, int, int);
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#include <linux/pci.h> #include <linux/pci.h>
extern struct sn_irq_info **sn_irq;
#define SN_PCIDEV_INFO(pci_dev) \ #define SN_PCIDEV_INFO(pci_dev) \
((struct pcidev_info *)(pci_dev)->sysdata) ((struct pcidev_info *)(pci_dev)->sysdata)
...@@ -50,9 +48,11 @@ struct pcidev_info { ...@@ -50,9 +48,11 @@ struct pcidev_info {
struct sn_irq_info *pdi_sn_irq_info; struct sn_irq_info *pdi_sn_irq_info;
struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ struct sn_pcibus_provider *pdi_provider; /* sn pci ops */
struct pci_dev *host_pci_dev; /* host bus link */
}; };
extern void sn_irq_fixup(struct pci_dev *pci_dev, extern void sn_irq_fixup(struct pci_dev *pci_dev,
struct sn_irq_info *sn_irq_info); struct sn_irq_info *sn_irq_info);
extern void sn_irq_lh_init(void);
#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ #endif /* _ASM_IA64_SN_PCI_PCIDEV_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment