int sn_force_interrupt_flag = 1;
extern int sn_ioif_inited;
-struct list_head **sn_irq_lh;
-static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */
+static struct list_head **sn_irq_lh;
+static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
-u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
- struct sn_irq_info *sn_irq_info,
+static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
+ u64 sn_irq_info,
int req_irq, nasid_t req_nasid,
int req_slice)
{
SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
(u64) SAL_INTR_ALLOC, (u64) local_nasid,
- (u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
+ (u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
(u64) req_nasid, (u64) req_slice);
-
return ret_stuff.status;
}
-void sn_intr_free(nasid_t local_nasid, int local_widget,
+static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
struct sn_irq_info *sn_irq_info)
{
struct ia64_sal_retval ret_stuff;
static void sn_irq_info_free(struct rcu_head *head);
-struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
- nasid_t nasid, int slice)
+static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
{
- int vector;
- int cpuphys;
- int64_t bridge;
- int local_widget, status;
- nasid_t local_nasid;
- struct sn_irq_info *new_irq_info;
- struct sn_pcibus_provider *pci_provider;
-
- new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
- if (new_irq_info == NULL)
- return NULL;
+ struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
+ int cpuid, cpuphys;
- memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+ cpuid = first_cpu(mask);
+ cpuphys = cpu_physical_id(cpuid);
- bridge = (u64) new_irq_info->irq_bridge;
- if (!bridge) {
- kfree(new_irq_info);
- return NULL; /* irq is not a device interrupt */
- }
+ list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+ sn_irq_lh[irq], list) {
+ u64 bridge;
+ int local_widget, status;
+ nasid_t local_nasid;
+ struct sn_irq_info *new_irq_info;
+ struct sn_pcibus_provider *pci_provider;
+
+ new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+ if (new_irq_info == NULL)
+ break;
+ memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
+ bridge = (u64) new_irq_info->irq_bridge;
+ if (!bridge) {
+ kfree(new_irq_info);
+ break; /* irq is not a device interrupt */
+ }
- local_nasid = NASID_GET(bridge);
+ local_nasid = NASID_GET(bridge);
- if (local_nasid & 1)
- local_widget = TIO_SWIN_WIDGETNUM(bridge);
- else
- local_widget = SWIN_WIDGETNUM(bridge);
+ if (local_nasid & 1)
+ local_widget = TIO_SWIN_WIDGETNUM(bridge);
+ else
+ local_widget = SWIN_WIDGETNUM(bridge);
- vector = sn_irq_info->irq_irq;
- /* Free the old PROM new_irq_info structure */
- sn_intr_free(local_nasid, local_widget, new_irq_info);
- /* Update kernels new_irq_info with new target info */
- unregister_intr_pda(new_irq_info);
+ /* Free the old PROM new_irq_info structure */
+ sn_intr_free(local_nasid, local_widget, new_irq_info);
+ /* Update kernels new_irq_info with new target info */
+ unregister_intr_pda(new_irq_info);
- /* allocate a new PROM new_irq_info struct */
- status = sn_intr_alloc(local_nasid, local_widget,
- new_irq_info, vector,
- nasid, slice);
+ /* allocate a new PROM new_irq_info struct */
+ status = sn_intr_alloc(local_nasid, local_widget,
+ __pa(new_irq_info), irq,
+ cpuid_to_nasid(cpuid),
+ cpuid_to_slice(cpuid));
- /* SAL call failed */
- if (status) {
- kfree(new_irq_info);
- return NULL;
- }
+ /* SAL call failed */
+ if (status) {
+ kfree(new_irq_info);
+ break;
+ }
- cpuphys = nasid_slice_to_cpuid(nasid, slice);
- new_irq_info->irq_cpuid = cpuphys;
- register_intr_pda(new_irq_info);
+ new_irq_info->irq_cpuid = cpuid;
+ register_intr_pda(new_irq_info);
- pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+ pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+ if (pci_provider && pci_provider->target_interrupt)
+ (pci_provider->target_interrupt)(new_irq_info);
- /*
- * If this represents a line interrupt, target it. If it's
- * an msi (irq_int_bit < 0), it's already targeted.
- */
- if (new_irq_info->irq_int_bit >= 0 &&
- pci_provider && pci_provider->target_interrupt)
- (pci_provider->target_interrupt)(new_irq_info);
-
- spin_lock(&sn_irq_info_lock);
- list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
- spin_unlock(&sn_irq_info_lock);
- call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+ spin_lock(&sn_irq_info_lock);
+ list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+ spin_unlock(&sn_irq_info_lock);
+ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
#ifdef CONFIG_SMP
- set_irq_affinity_info((vector & 0xff), cpuphys, 0);
+ set_irq_affinity_info((irq & 0xff), cpuphys, 0);
#endif
-
- return new_irq_info;
-}
-
-static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
-{
- struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
- nasid_t nasid;
- int slice;
-
- nasid = cpuid_to_nasid(first_cpu(mask));
- slice = cpuid_to_slice(first_cpu(mask));
-
- list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
- sn_irq_lh[irq], list)
- (void)sn_retarget_vector(sn_irq_info, nasid, slice);
+ }
}
struct hw_interrupt_type irq_type_sn = {
int i;
irq_desc_t *base_desc = irq_desc;
- ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
- ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
-
for (i = 0; i < NR_IRQS; i++) {
- if (base_desc[i].chip == &no_irq_type) {
- base_desc[i].chip = &irq_type_sn;
+ if (base_desc[i].handler == &no_irq_type) {
+ base_desc[i].handler = &irq_type_sn;
}
}
}
/* link it into the sn_irq[irq] list */
spin_lock(&sn_irq_info_lock);
list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
- reserve_irq_vector(sn_irq_info->irq_irq);
spin_unlock(&sn_irq_info_lock);
register_intr_pda(sn_irq_info);
spin_lock(&sn_irq_info_lock);
list_del_rcu(&sn_irq_info->list);
spin_unlock(&sn_irq_info_lock);
- if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
- free_irq_vector(sn_irq_info->irq_irq);
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
pci_dev_put(pci_dev);
-
}
static inline void
static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
{
u64 regval;
+ int irr_reg_num;
+ int irr_bit;
+ u64 irr_reg;
struct pcidev_info *pcidev_info;
struct pcibus_info *pcibus_info;
pdi_pcibus_info;
regval = pcireg_intr_status_get(pcibus_info);
- if (!ia64_get_irr(irq_to_vector(irq))) {
+ irr_reg_num = irq_to_vector(irq) / 64;
+ irr_bit = irq_to_vector(irq) % 64;
+ switch (irr_reg_num) {
+ case 0:
+ irr_reg = ia64_getreg(_IA64_REG_CR_IRR0);
+ break;
+ case 1:
+ irr_reg = ia64_getreg(_IA64_REG_CR_IRR1);
+ break;
+ case 2:
+ irr_reg = ia64_getreg(_IA64_REG_CR_IRR2);
+ break;
+ case 3:
+ irr_reg = ia64_getreg(_IA64_REG_CR_IRR3);
+ break;
+ }
+ if (!test_bit(irr_bit, &irr_reg)) {
if (!test_bit(irq, pda->sn_in_service_ivecs)) {
regval &= 0xff;
if (sn_irq_info->irq_int_bit & regval &