aboutsummaryrefslogtreecommitdiff
path: root/arch/ia64/kernel/iosapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/iosapic.c')
-rw-r--r--arch/ia64/kernel/iosapic.c175
1 files changed, 94 insertions, 81 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 22c38404f53..cd44a57c73b 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -76,7 +76,7 @@
* PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
*
* Note: The term "IRQ" is loosely used everywhere in Linux kernel to
- * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ
+ * describe interrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ
* (isa_irq) is the only exception in this source code.
*/
@@ -98,7 +98,6 @@
#include <asm/machvec.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
-#include <asm/system.h>
#undef DEBUG_INTERRUPT_ROUTING
@@ -148,7 +147,7 @@ static struct iosapic_intr_info {
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
} iosapic_intr_info[NR_IRQS];
-static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
+static unsigned char pcat_compat; /* 8259 compatibility flag */
static inline void
iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
@@ -257,7 +256,7 @@ set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
}
static void
-nop (unsigned int irq)
+nop (struct irq_data *data)
{
/* do nothing... */
}
@@ -287,8 +286,9 @@ kexec_disable_iosapic(void)
#endif
static void
-mask_irq (unsigned int irq)
+mask_irq (struct irq_data *data)
{
+ unsigned int irq = data->irq;
u32 low32;
int rte_index;
struct iosapic_rte_info *rte;
@@ -305,8 +305,9 @@ mask_irq (unsigned int irq)
}
static void
-unmask_irq (unsigned int irq)
+unmask_irq (struct irq_data *data)
{
+ unsigned int irq = data->irq;
u32 low32;
int rte_index;
struct iosapic_rte_info *rte;
@@ -323,9 +324,11 @@ unmask_irq (unsigned int irq)
static int
-iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
+iosapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
{
#ifdef CONFIG_SMP
+ unsigned int irq = data->irq;
u32 high32, low32;
int cpu, dest, rte_index;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
@@ -379,32 +382,33 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
*/
static unsigned int
-iosapic_startup_level_irq (unsigned int irq)
+iosapic_startup_level_irq (struct irq_data *data)
{
- unmask_irq(irq);
+ unmask_irq(data);
return 0;
}
static void
-iosapic_unmask_level_irq (unsigned int irq)
+iosapic_unmask_level_irq (struct irq_data *data)
{
+ unsigned int irq = data->irq;
ia64_vector vec = irq_to_vector(irq);
struct iosapic_rte_info *rte;
int do_unmask_irq = 0;
irq_complete_move(irq);
- if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+ if (unlikely(irqd_is_setaffinity_pending(data))) {
do_unmask_irq = 1;
- mask_irq(irq);
+ mask_irq(data);
} else
- unmask_irq(irq);
+ unmask_irq(data);
list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
iosapic_eoi(rte->iosapic->addr, vec);
if (unlikely(do_unmask_irq)) {
- move_masked_irq(irq);
- unmask_irq(irq);
+ irq_move_masked_irq(data);
+ unmask_irq(data);
}
}
@@ -414,15 +418,15 @@ iosapic_unmask_level_irq (unsigned int irq)
#define iosapic_ack_level_irq nop
static struct irq_chip irq_type_iosapic_level = {
- .name = "IO-SAPIC-level",
- .startup = iosapic_startup_level_irq,
- .shutdown = iosapic_shutdown_level_irq,
- .enable = iosapic_enable_level_irq,
- .disable = iosapic_disable_level_irq,
- .ack = iosapic_ack_level_irq,
- .mask = mask_irq,
- .unmask = iosapic_unmask_level_irq,
- .set_affinity = iosapic_set_affinity
+ .name = "IO-SAPIC-level",
+ .irq_startup = iosapic_startup_level_irq,
+ .irq_shutdown = iosapic_shutdown_level_irq,
+ .irq_enable = iosapic_enable_level_irq,
+ .irq_disable = iosapic_disable_level_irq,
+ .irq_ack = iosapic_ack_level_irq,
+ .irq_mask = mask_irq,
+ .irq_unmask = iosapic_unmask_level_irq,
+ .irq_set_affinity = iosapic_set_affinity
};
/*
@@ -430,9 +434,9 @@ static struct irq_chip irq_type_iosapic_level = {
*/
static unsigned int
-iosapic_startup_edge_irq (unsigned int irq)
+iosapic_startup_edge_irq (struct irq_data *data)
{
- unmask_irq(irq);
+ unmask_irq(data);
/*
* IOSAPIC simply drops interrupts pended while the
* corresponding pin was masked, so we can't know if an
@@ -442,37 +446,25 @@ iosapic_startup_edge_irq (unsigned int irq)
}
static void
-iosapic_ack_edge_irq (unsigned int irq)
+iosapic_ack_edge_irq (struct irq_data *data)
{
- struct irq_desc *idesc = irq_desc + irq;
-
- irq_complete_move(irq);
- move_native_irq(irq);
- /*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
- if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) ==
- (IRQ_PENDING|IRQ_DISABLED))
- mask_irq(irq);
+ irq_complete_move(data->irq);
+ irq_move_irq(data);
}
#define iosapic_enable_edge_irq unmask_irq
#define iosapic_disable_edge_irq nop
-#define iosapic_end_edge_irq nop
static struct irq_chip irq_type_iosapic_edge = {
- .name = "IO-SAPIC-edge",
- .startup = iosapic_startup_edge_irq,
- .shutdown = iosapic_disable_edge_irq,
- .enable = iosapic_enable_edge_irq,
- .disable = iosapic_disable_edge_irq,
- .ack = iosapic_ack_edge_irq,
- .end = iosapic_end_edge_irq,
- .mask = mask_irq,
- .unmask = unmask_irq,
- .set_affinity = iosapic_set_affinity
+ .name = "IO-SAPIC-edge",
+ .irq_startup = iosapic_startup_edge_irq,
+ .irq_shutdown = iosapic_disable_edge_irq,
+ .irq_enable = iosapic_enable_edge_irq,
+ .irq_disable = iosapic_disable_edge_irq,
+ .irq_ack = iosapic_ack_edge_irq,
+ .irq_mask = mask_irq,
+ .irq_unmask = unmask_irq,
+ .irq_set_affinity = iosapic_set_affinity
};
static unsigned int
@@ -562,8 +554,7 @@ static int
register_intr (unsigned int gsi, int irq, unsigned char delivery,
unsigned long polarity, unsigned long trigger)
{
- struct irq_desc *idesc;
- struct irq_chip *irq_type;
+ struct irq_chip *chip, *irq_type;
int index;
struct iosapic_rte_info *rte;
@@ -610,19 +601,18 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
irq_type = iosapic_get_irq_chip(trigger);
- idesc = irq_desc + irq;
- if (irq_type != NULL && idesc->chip != irq_type) {
- if (idesc->chip != &no_irq_chip)
+ chip = irq_get_chip(irq);
+ if (irq_type != NULL && chip != irq_type) {
+ if (chip != &no_irq_chip)
printk(KERN_WARNING
"%s: changing vector %d from %s to %s\n",
__func__, irq_to_vector(irq),
- idesc->chip->name, irq_type->name);
- idesc->chip = irq_type;
+ chip->name, irq_type->name);
+ chip = irq_type;
}
- if (trigger == IOSAPIC_EDGE)
- __set_irq_handler_unlocked(irq, handle_edge_irq);
- else
- __set_irq_handler_unlocked(irq, handle_level_irq);
+ __irq_set_chip_handler_name_locked(irq, chip, trigger == IOSAPIC_EDGE ?
+ handle_edge_irq : handle_level_irq,
+ NULL);
return 0;
}
@@ -732,6 +722,7 @@ iosapic_register_intr (unsigned int gsi,
struct iosapic_rte_info *rte;
u32 low32;
unsigned char dmode;
+ struct irq_desc *desc;
/*
* If this GSI has already been registered (i.e., it's a
@@ -744,7 +735,7 @@ iosapic_register_intr (unsigned int gsi,
rte = find_rte(irq, gsi);
if(iosapic_intr_info[irq].count == 0) {
assign_irq_vector(irq);
- dynamic_irq_init(irq);
+ irq_init_desc(irq);
} else if (rte->refcnt != NO_REF_RTE) {
rte->refcnt++;
goto unlock_iosapic_lock;
@@ -759,12 +750,13 @@ iosapic_register_intr (unsigned int gsi,
goto unlock_iosapic_lock;
}
- raw_spin_lock(&irq_desc[irq].lock);
+ desc = irq_to_desc(irq);
+ raw_spin_lock(&desc->lock);
dest = get_target_cpu(gsi, irq);
dmode = choose_dmode();
err = register_intr(gsi, irq, dmode, polarity, trigger);
if (err < 0) {
- raw_spin_unlock(&irq_desc[irq].lock);
+ raw_spin_unlock(&desc->lock);
irq = err;
goto unlock_iosapic_lock;
}
@@ -783,7 +775,7 @@ iosapic_register_intr (unsigned int gsi,
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, irq_to_vector(irq));
- raw_spin_unlock(&irq_desc[irq].lock);
+ raw_spin_unlock(&desc->lock);
unlock_iosapic_lock:
spin_unlock_irqrestore(&iosapic_lock, flags);
return irq;
@@ -794,7 +786,6 @@ iosapic_unregister_intr (unsigned int gsi)
{
unsigned long flags;
int irq, index;
- struct irq_desc *idesc;
u32 low32;
unsigned long trigger, polarity;
unsigned int dest;
@@ -824,7 +815,6 @@ iosapic_unregister_intr (unsigned int gsi)
if (--rte->refcnt > 0)
goto out;
- idesc = irq_desc + irq;
rte->refcnt = NO_REF_RTE;
/* Mask the interrupt */
@@ -848,7 +838,7 @@ iosapic_unregister_intr (unsigned int gsi)
if (iosapic_intr_info[irq].count == 0) {
#ifdef CONFIG_SMP
/* Clear affinity */
- cpumask_setall(idesc->affinity);
+ cpumask_setall(irq_get_irq_data(irq)->affinity);
#endif
/* Clear the interrupt information */
iosapic_intr_info[irq].dest = 0;
@@ -924,10 +914,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
/*
* ACPI calls this when it finds an entry for a legacy ISA IRQ override.
*/
-void __devinit
-iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
- unsigned long polarity,
- unsigned long trigger)
+void iosapic_override_isa_irq(unsigned int isa_irq, unsigned int gsi,
+ unsigned long polarity, unsigned long trigger)
{
int vector, irq;
unsigned int dest = cpu_physical_id(smp_processor_id());
@@ -1022,8 +1010,27 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
return 0;
}
-int __devinit
-iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
+static int
+iosapic_delete_rte(unsigned int irq, unsigned int gsi)
+{
+ struct iosapic_rte_info *rte, *temp;
+
+ list_for_each_entry_safe(rte, temp, &iosapic_intr_info[irq].rtes,
+ rte_list) {
+ if (rte->iosapic->gsi_base + rte->rte_index == gsi) {
+ if (rte->refcnt)
+ return -EBUSY;
+
+ list_del(&rte->rte_list);
+ kfree(rte);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
{
int num_rte, err, index;
unsigned int isa_irq, ver;
@@ -1080,11 +1087,9 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
return 0;
}
-#ifdef CONFIG_HOTPLUG
-int
-iosapic_remove (unsigned int gsi_base)
+int iosapic_remove(unsigned int gsi_base)
{
- int index, err = 0;
+ int i, irq, index, err = 0;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
@@ -1102,17 +1107,25 @@ iosapic_remove (unsigned int gsi_base)
goto out;
}
+ for (i = gsi_base; i < gsi_base + iosapic_lists[index].num_rte; i++) {
+ irq = __gsi_to_irq(i);
+ if (irq < 0)
+ continue;
+
+ err = iosapic_delete_rte(irq, i);
+ if (err)
+ goto out;
+ }
+
iounmap(iosapic_lists[index].addr);
iosapic_free(index);
out:
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
}
-#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_NUMA
-void __devinit
-map_iosapic_to_node(unsigned int gsi_base, int node)
+void map_iosapic_to_node(unsigned int gsi_base, int node)
{
int index;