diff options
| author | Tony Luck <tony.luck@intel.com> | 2005-06-29 15:21:41 -0700 | 
|---|---|---|
| committer | Tony Luck <tony.luck@intel.com> | 2005-06-29 15:21:41 -0700 | 
| commit | d18bfacff20f08aecf01bb971b110ca108eef3c7 (patch) | |
| tree | 255f862839c593c796e609328575b611e3f56cf3 /arch/ia64/kernel/iosapic.c | |
| parent | a68db763af9b676590c3fe9ec3f17bf18015eb2f (diff) | |
| parent | fd782a4a99d2d3e818b9465c427b10f7f027d7da (diff) | |
Auto merge with /home/aegl/GIT/linus
Diffstat (limited to 'arch/ia64/kernel/iosapic.c')
| -rw-r--r-- | arch/ia64/kernel/iosapic.c | 134 | 
1 files changed, 113 insertions, 21 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 88b014381df5..c170be095ccd 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -129,14 +129,13 @@ static struct iosapic {  	char __iomem	*addr;		/* base address of IOSAPIC */  	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */  	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */ +	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */  #ifdef CONFIG_NUMA  	unsigned short	node;		/* numa node association via pxm */  #endif  } iosapic_lists[NR_IOSAPICS]; -static int num_iosapic; - -static unsigned char pcat_compat __initdata;	/* 8259 compatibility flag */ +static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */  static int iosapic_kmalloc_ok;  static LIST_HEAD(free_rte_list); @@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)  {  	int i; -	for (i = 0; i < num_iosapic; i++) { +	for (i = 0; i < NR_IOSAPICS; i++) {  		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)  			return i;  	} @@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,  		rte->refcnt++;  		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);  		iosapic_intr_info[vector].count++; +		iosapic_lists[index].rtes_inuse++;  	}  	else if (vector_is_shared(vector)) {  		struct iosapic_intr_info *info = &iosapic_intr_info[vector]; @@ -778,7 +778,7 @@ void  iosapic_unregister_intr (unsigned int gsi)  {  	unsigned long flags; -	int irq, vector; +	int irq, vector, index;  	irq_desc_t *idesc;  	u32 low32;  	unsigned long trigger, polarity; @@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)  		list_del(&rte->rte_list);  		iosapic_intr_info[vector].count--;  		iosapic_free_rte(rte); +		index = find_iosapic(gsi); +		iosapic_lists[index].rtes_inuse--; +		WARN_ON(iosapic_lists[index].rtes_inuse < 0);  		trigger	 = iosapic_intr_info[vector].trigger;  		polarity = iosapic_intr_info[vector].polarity; @@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)  	}  } -void __init +static inline int +iosapic_alloc (void) +{ +	int index; + +	for (index = 0; index < NR_IOSAPICS; index++) +		if (!iosapic_lists[index].addr) +			return index; + +	printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); +	return -1; +} + +static inline void +iosapic_free (int index) +{ +	memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); +} + +static inline int +iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) +{ +	int index; +	unsigned int gsi_end, base, end; + +	/* check gsi range */ +	gsi_end = gsi_base + ((ver >> 16) & 0xff); +	for (index = 0; index < NR_IOSAPICS; index++) { +		if (!iosapic_lists[index].addr) +			continue; + +		base = iosapic_lists[index].gsi_base; +		end  = base + iosapic_lists[index].num_rte - 1; + +		if (gsi_base < base && gsi_end < base) +			continue;/* OK */ + +		if (gsi_base > end && gsi_end > end) +			continue; /* OK */ + +		return -EBUSY; +	} +	return 0; +} + +int __devinit  iosapic_init (unsigned long phys_addr, unsigned int gsi_base)  { -	int num_rte; +	int num_rte, err, index;  	unsigned int isa_irq, ver;  	char __iomem *addr; +	unsigned long flags; + +	spin_lock_irqsave(&iosapic_lock, flags); +	{ +		addr = ioremap(phys_addr, 0); +		ver = iosapic_version(addr); -	addr = ioremap(phys_addr, 0); -	ver = iosapic_version(addr); +		if ((err = iosapic_check_gsi_range(gsi_base, ver))) { +			iounmap(addr); +			spin_unlock_irqrestore(&iosapic_lock, flags); +			return err; +		} -	/* -	 * The MAX_REDIR register holds the highest input pin -	 * number (starting from 0). -	 * We add 1 so that we can use it for number of pins (= RTEs) -	 */ -	num_rte = ((ver >> 16) & 0xff) + 1; +		/* +		 * The MAX_REDIR register holds the highest input pin +		 * number (starting from 0). +		 * We add 1 so that we can use it for number of pins (= RTEs) +		 */ +		num_rte = ((ver >> 16) & 0xff) + 1; -	iosapic_lists[num_iosapic].addr = addr; -	iosapic_lists[num_iosapic].gsi_base = gsi_base; -	iosapic_lists[num_iosapic].num_rte = num_rte; +		index = iosapic_alloc(); +		iosapic_lists[index].addr = addr; +		iosapic_lists[index].gsi_base = gsi_base; +		iosapic_lists[index].num_rte = num_rte;  #ifdef CONFIG_NUMA -	iosapic_lists[num_iosapic].node = MAX_NUMNODES; +		iosapic_lists[index].node = MAX_NUMNODES;  #endif -	num_iosapic++; +	} +	spin_unlock_irqrestore(&iosapic_lock, flags);  	if ((gsi_base == 0) && pcat_compat) {  		/* @@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)  		for (isa_irq = 0; isa_irq < 16; ++isa_irq)  			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);  	} +	return 0; +} + +#ifdef CONFIG_HOTPLUG +int +iosapic_remove (unsigned int gsi_base) +{ +	int index, err = 0; +	unsigned long flags; + +	spin_lock_irqsave(&iosapic_lock, flags); +	{ +		index = find_iosapic(gsi_base); +		if (index < 0) { +			printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", +			       __FUNCTION__, gsi_base); +			goto out; +		} + +		if (iosapic_lists[index].rtes_inuse) { +			err = -EBUSY; +			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", +			       __FUNCTION__, gsi_base); +			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 __init +void __devinit  map_iosapic_to_node(unsigned int gsi_base, int node)  {  	int index;  | 
