diff options
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
| -rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 784 | 
1 files changed, 488 insertions, 296 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 81e08eff05ee..337ce5a9b15c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -31,6 +31,7 @@  #include <linux/acpi.h>  #include <linux/module.h>  #include <linux/syscore_ops.h> +#include <linux/irqdomain.h>  #include <linux/msi.h>  #include <linux/htirq.h>  #include <linux/freezer.h> @@ -62,6 +63,16 @@  #define __apicdebuginit(type) static type __init +#define	for_each_ioapic(idx)		\ +	for ((idx) = 0; (idx) < nr_ioapics; (idx)++) +#define	for_each_ioapic_reverse(idx)	\ +	for ((idx) = nr_ioapics - 1; (idx) >= 0; (idx)--) +#define	for_each_pin(idx, pin)		\ +	for ((pin) = 0; (pin) < ioapics[(idx)].nr_registers; (pin)++) +#define	for_each_ioapic_pin(idx, pin)	\ +	for_each_ioapic((idx))		\ +		for_each_pin((idx), (pin)) +  #define for_each_irq_pin(entry, head) \  	for (entry = head; entry; entry = entry->next) @@ -73,6 +84,17 @@ int sis_apic_bug = -1;  static DEFINE_RAW_SPINLOCK(ioapic_lock);  static DEFINE_RAW_SPINLOCK(vector_lock); +static DEFINE_MUTEX(ioapic_mutex); +static unsigned int ioapic_dynirq_base; +static int ioapic_initialized; + +struct mp_pin_info { +	int trigger; +	int polarity; +	int node; +	int set; +	u32 count; +};  static struct ioapic {  	/* @@ -87,7 +109,9 @@ static struct ioapic {  	struct mpc_ioapic mp_config;  	/* IO APIC gsi routing info */  	struct mp_ioapic_gsi  gsi_config; -	DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); +	struct ioapic_domain_cfg irqdomain_cfg; +	struct irq_domain *irqdomain; +	struct mp_pin_info *pin_info;  } ioapics[MAX_IO_APICS];  #define mpc_ioapic_ver(ioapic_idx)	ioapics[ioapic_idx].mp_config.apicver @@ -107,6 +131,41 @@ struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)  	return &ioapics[ioapic_idx].gsi_config;  } +static inline int mp_ioapic_pin_count(int ioapic) +{ +	struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic); + +	return gsi_cfg->gsi_end - gsi_cfg->gsi_base + 1; +} + +u32 mp_pin_to_gsi(int ioapic, int pin) +{ +	return mp_ioapic_gsi_routing(ioapic)->gsi_base + pin; +} + +/* + * Initialize all legacy IRQs and all pins on the first IOAPIC + * if we have legacy interrupt controller. Kernel boot option "pirq=" + * may rely on non-legacy pins on the first IOAPIC. + */ +static inline int mp_init_irq_at_boot(int ioapic, int irq) +{ +	if (!nr_legacy_irqs()) +		return 0; + +	return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs()); +} + +static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin) +{ +	return ioapics[ioapic_idx].pin_info + pin; +} + +static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic) +{ +	return ioapics[ioapic].irqdomain; +} +  int nr_ioapics;  /* The one past the highest gsi number used */ @@ -118,9 +177,6 @@ struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];  /* # of MP IRQ source entries */  int mp_irq_entries; -/* GSI interrupts */ -static int nr_irqs_gsi = NR_IRQS_LEGACY; -  #ifdef CONFIG_EISA  int mp_bus_id_to_type[MAX_MP_BUSSES];  #endif @@ -149,8 +205,7 @@ static int __init parse_noapic(char *str)  }  early_param("noapic", parse_noapic); -static int io_apic_setup_irq_pin(unsigned int irq, int node, -				 struct io_apic_irq_attr *attr); +static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node);  /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */  void mp_save_irq(struct mpc_intsrc *m) @@ -182,19 +237,15 @@ static struct irq_pin_list *alloc_irq_pin_list(int node)  	return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);  } - -/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ -static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY]; -  int __init arch_early_irq_init(void)  {  	struct irq_cfg *cfg; -	int count, node, i; +	int i, node = cpu_to_node(0); -	if (!legacy_pic->nr_legacy_irqs) +	if (!nr_legacy_irqs())  		io_apic_irqs = ~0UL; -	for (i = 0; i < nr_ioapics; i++) { +	for_each_ioapic(i) {  		ioapics[i].saved_registers =  			kzalloc(sizeof(struct IO_APIC_route_entry) *  				ioapics[i].nr_registers, GFP_KERNEL); @@ -202,28 +253,20 @@ int __init arch_early_irq_init(void)  			pr_err("IOAPIC %d: suspend/resume impossible!\n", i);  	} -	cfg = irq_cfgx; -	count = ARRAY_SIZE(irq_cfgx); -	node = cpu_to_node(0); - -	for (i = 0; i < count; i++) { -		irq_set_chip_data(i, &cfg[i]); -		zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node); -		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node); -		/* -		 * For legacy IRQ's, start with assigning irq0 to irq15 to -		 * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's. -		 */ -		if (i < legacy_pic->nr_legacy_irqs) { -			cfg[i].vector = IRQ0_VECTOR + i; -			cpumask_setall(cfg[i].domain); -		} +	/* +	 * For legacy IRQ's, start with assigning irq0 to irq15 to +	 * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's. +	 */ +	for (i = 0; i < nr_legacy_irqs(); i++) { +		cfg = alloc_irq_and_cfg_at(i, node); +		cfg->vector = IRQ0_VECTOR + i; +		cpumask_setall(cfg->domain);  	}  	return 0;  } -static struct irq_cfg *irq_cfg(unsigned int irq) +static inline struct irq_cfg *irq_cfg(unsigned int irq)  {  	return irq_get_chip_data(irq);  } @@ -265,7 +308,7 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)  	if (res < 0) {  		if (res != -EEXIST)  			return NULL; -		cfg = irq_get_chip_data(at); +		cfg = irq_cfg(at);  		if (cfg)  			return cfg;  	} @@ -425,6 +468,21 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi  	return 0;  } +static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin) +{ +	struct irq_pin_list **last, *entry; + +	last = &cfg->irq_2_pin; +	for_each_irq_pin(entry, cfg->irq_2_pin) +		if (entry->apic == apic && entry->pin == pin) { +			*last = entry->next; +			kfree(entry); +			return; +		} else { +			last = &entry->next; +		} +} +  static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)  {  	if (__add_pin_to_irq_node(cfg, node, apic, pin)) @@ -627,9 +685,8 @@ static void clear_IO_APIC (void)  {  	int apic, pin; -	for (apic = 0; apic < nr_ioapics; apic++) -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) -			clear_IO_APIC_pin(apic, pin); +	for_each_ioapic_pin(apic, pin) +		clear_IO_APIC_pin(apic, pin);  }  #ifdef CONFIG_X86_32 @@ -678,13 +735,13 @@ int save_ioapic_entries(void)  	int apic, pin;  	int err = 0; -	for (apic = 0; apic < nr_ioapics; apic++) { +	for_each_ioapic(apic) {  		if (!ioapics[apic].saved_registers) {  			err = -ENOMEM;  			continue;  		} -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) +		for_each_pin(apic, pin)  			ioapics[apic].saved_registers[pin] =  				ioapic_read_entry(apic, pin);  	} @@ -699,11 +756,11 @@ void mask_ioapic_entries(void)  {  	int apic, pin; -	for (apic = 0; apic < nr_ioapics; apic++) { +	for_each_ioapic(apic) {  		if (!ioapics[apic].saved_registers)  			continue; -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) { +		for_each_pin(apic, pin) {  			struct IO_APIC_route_entry entry;  			entry = ioapics[apic].saved_registers[pin]; @@ -722,11 +779,11 @@ int restore_ioapic_entries(void)  {  	int apic, pin; -	for (apic = 0; apic < nr_ioapics; apic++) { +	for_each_ioapic(apic) {  		if (!ioapics[apic].saved_registers)  			continue; -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) +		for_each_pin(apic, pin)  			ioapic_write_entry(apic, pin,  					   ioapics[apic].saved_registers[pin]);  	} @@ -785,7 +842,7 @@ static int __init find_isa_irq_apic(int irq, int type)  	if (i < mp_irq_entries) {  		int ioapic_idx; -		for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) +		for_each_ioapic(ioapic_idx)  			if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic)  				return ioapic_idx;  	} @@ -799,7 +856,7 @@ static int __init find_isa_irq_apic(int irq, int type)   */  static int EISA_ELCR(unsigned int irq)  { -	if (irq < legacy_pic->nr_legacy_irqs) { +	if (irq < nr_legacy_irqs()) {  		unsigned int port = 0x4d0 + (irq >> 3);  		return (inb(port) >> (irq & 7)) & 1;  	} @@ -939,29 +996,106 @@ static int irq_trigger(int idx)  	return trigger;  } -static int pin_2_irq(int idx, int apic, int pin) +static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin) +{ +	int irq = -1; +	int ioapic = (int)(long)domain->host_data; +	int type = ioapics[ioapic].irqdomain_cfg.type; + +	switch (type) { +	case IOAPIC_DOMAIN_LEGACY: +		/* +		 * Dynamically allocate IRQ number for non-ISA IRQs in the first 16 +		 * GSIs on some weird platforms. +		 */ +		if (gsi < nr_legacy_irqs()) +			irq = irq_create_mapping(domain, pin); +		else if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0) +			irq = gsi; +		break; +	case IOAPIC_DOMAIN_STRICT: +		if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0) +			irq = gsi; +		break; +	case IOAPIC_DOMAIN_DYNAMIC: +		irq = irq_create_mapping(domain, pin); +		break; +	default: +		WARN(1, "ioapic: unknown irqdomain type %d\n", type); +		break; +	} + +	return irq > 0 ? irq : -1; +} + +static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, +			     unsigned int flags)  {  	int irq; -	int bus = mp_irqs[idx].srcbus; -	struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(apic); +	struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); +	struct mp_pin_info *info = mp_pin_info(ioapic, pin); + +	if (!domain) +		return -1; + +	mutex_lock(&ioapic_mutex);  	/* -	 * Debugging check, we are in big trouble if this message pops up! +	 * Don't use irqdomain to manage ISA IRQs because there may be +	 * multiple IOAPIC pins sharing the same ISA IRQ number and +	 * irqdomain only supports 1:1 mapping between IOAPIC pin and +	 * IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are used +	 * for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H). +	 * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are +	 * available, and some BIOSes may use MP Interrupt Source records +	 * to override IRQ numbers for PIRQs instead of reprogramming +	 * the interrupt routing logic. Thus there may be multiple pins +	 * sharing the same legacy IRQ number when ACPI is disabled.  	 */ -	if (mp_irqs[idx].dstirq != pin) -		pr_err("broken BIOS or MPTABLE parser, ayiee!!\n"); - -	if (test_bit(bus, mp_bus_not_pci)) { +	if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {  		irq = mp_irqs[idx].srcbusirq; +		if (flags & IOAPIC_MAP_ALLOC) { +			if (info->count == 0 && +			    mp_irqdomain_map(domain, irq, pin) != 0) +				irq = -1; + +			/* special handling for timer IRQ0 */ +			if (irq == 0) +				info->count++; +		}  	} else { -		u32 gsi = gsi_cfg->gsi_base + pin; +		irq = irq_find_mapping(domain, pin); +		if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) +			irq = alloc_irq_from_domain(domain, gsi, pin); +	} -		if (gsi >= NR_IRQS_LEGACY) -			irq = gsi; -		else -			irq = gsi_top + gsi; +	if (flags & IOAPIC_MAP_ALLOC) { +		/* special handling for legacy IRQs */ +		if (irq < nr_legacy_irqs() && info->count == 1 && +		    mp_irqdomain_map(domain, irq, pin) != 0) +			irq = -1; + +		if (irq > 0) +			info->count++; +		else if (info->count == 0) +			info->set = 0;  	} +	mutex_unlock(&ioapic_mutex); + +	return irq > 0 ? irq : -1; +} + +static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags) +{ +	u32 gsi = mp_pin_to_gsi(ioapic, pin); + +	/* +	 * Debugging check, we are in big trouble if this message pops up! +	 */ +	if (mp_irqs[idx].dstirq != pin) +		pr_err("broken BIOS or MPTABLE parser, ayiee!!\n"); +  #ifdef CONFIG_X86_32  	/*  	 * PCI IRQ command line redirection. Yes, limits are hardcoded. @@ -972,16 +1106,58 @@ static int pin_2_irq(int idx, int apic, int pin)  				apic_printk(APIC_VERBOSE, KERN_DEBUG  						"disabling PIRQ%d\n", pin-16);  			} else { -				irq = pirq_entries[pin-16]; +				int irq = pirq_entries[pin-16];  				apic_printk(APIC_VERBOSE, KERN_DEBUG  						"using PIRQ%d -> IRQ %d\n",  						pin-16, irq); +				return irq;  			}  		}  	}  #endif -	return irq; +	return  mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); +} + +int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) +{ +	int ioapic, pin, idx; + +	ioapic = mp_find_ioapic(gsi); +	if (ioapic < 0) +		return -1; + +	pin = mp_find_ioapic_pin(ioapic, gsi); +	idx = find_irq_entry(ioapic, pin, mp_INT); +	if ((flags & IOAPIC_MAP_CHECK) && idx < 0) +		return -1; + +	return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); +} + +void mp_unmap_irq(int irq) +{ +	struct irq_data *data = irq_get_irq_data(irq); +	struct mp_pin_info *info; +	int ioapic, pin; + +	if (!data || !data->domain) +		return; + +	ioapic = (int)(long)data->domain->host_data; +	pin = (int)data->hwirq; +	info = mp_pin_info(ioapic, pin); + +	mutex_lock(&ioapic_mutex); +	if (--info->count == 0) { +		info->set = 0; +		if (irq < nr_legacy_irqs() && +		    ioapics[ioapic].irqdomain_cfg.type == IOAPIC_DOMAIN_LEGACY) +			mp_irqdomain_unmap(data->domain, irq); +		else +			irq_dispose_mapping(irq); +	} +	mutex_unlock(&ioapic_mutex);  }  /* @@ -991,7 +1167,7 @@ static int pin_2_irq(int idx, int apic, int pin)  int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,  				struct io_apic_irq_attr *irq_attr)  { -	int ioapic_idx, i, best_guess = -1; +	int irq, i, best_ioapic = -1, best_idx = -1;  	apic_printk(APIC_DEBUG,  		    "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", @@ -1001,44 +1177,56 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,  			    "PCI BIOS passed nonexistent PCI bus %d!\n", bus);  		return -1;  	} +  	for (i = 0; i < mp_irq_entries; i++) {  		int lbus = mp_irqs[i].srcbus; +		int ioapic_idx, found = 0; -		for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) +		if (bus != lbus || mp_irqs[i].irqtype != mp_INT || +		    slot != ((mp_irqs[i].srcbusirq >> 2) & 0x1f)) +			continue; + +		for_each_ioapic(ioapic_idx)  			if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic || -			    mp_irqs[i].dstapic == MP_APIC_ALL) +			    mp_irqs[i].dstapic == MP_APIC_ALL) { +				found = 1;  				break; +			} +		if (!found) +			continue; -		if (!test_bit(lbus, mp_bus_not_pci) && -		    !mp_irqs[i].irqtype && -		    (bus == lbus) && -		    (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) { -			int irq = pin_2_irq(i, ioapic_idx, mp_irqs[i].dstirq); +		/* Skip ISA IRQs */ +		irq = pin_2_irq(i, ioapic_idx, mp_irqs[i].dstirq, 0); +		if (irq > 0 && !IO_APIC_IRQ(irq)) +			continue; -			if (!(ioapic_idx || IO_APIC_IRQ(irq))) -				continue; +		if (pin == (mp_irqs[i].srcbusirq & 3)) { +			best_idx = i; +			best_ioapic = ioapic_idx; +			goto out; +		} -			if (pin == (mp_irqs[i].srcbusirq & 3)) { -				set_io_apic_irq_attr(irq_attr, ioapic_idx, -						     mp_irqs[i].dstirq, -						     irq_trigger(i), -						     irq_polarity(i)); -				return irq; -			} -			/* -			 * Use the first all-but-pin matching entry as a -			 * best-guess fuzzy result for broken mptables. -			 */ -			if (best_guess < 0) { -				set_io_apic_irq_attr(irq_attr, ioapic_idx, -						     mp_irqs[i].dstirq, -						     irq_trigger(i), -						     irq_polarity(i)); -				best_guess = irq; -			} +		/* +		 * Use the first all-but-pin matching entry as a +		 * best-guess fuzzy result for broken mptables. +		 */ +		if (best_idx < 0) { +			best_idx = i; +			best_ioapic = ioapic_idx;  		}  	} -	return best_guess; +	if (best_idx < 0) +		return -1; + +out: +	irq = pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq, +			IOAPIC_MAP_ALLOC); +	if (irq > 0) +		set_io_apic_irq_attr(irq_attr, best_ioapic, +				     mp_irqs[best_idx].dstirq, +				     irq_trigger(best_idx), +				     irq_polarity(best_idx)); +	return irq;  }  EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); @@ -1198,7 +1386,7 @@ void __setup_vector_irq(int cpu)  	raw_spin_lock(&vector_lock);  	/* Mark the inuse vectors */  	for_each_active_irq(irq) { -		cfg = irq_get_chip_data(irq); +		cfg = irq_cfg(irq);  		if (!cfg)  			continue; @@ -1227,12 +1415,10 @@ static inline int IO_APIC_irq_trigger(int irq)  {  	int apic, idx, pin; -	for (apic = 0; apic < nr_ioapics; apic++) { -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) { -			idx = find_irq_entry(apic, pin, mp_INT); -			if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin))) -				return irq_trigger(idx); -		} +	for_each_ioapic_pin(apic, pin) { +		idx = find_irq_entry(apic, pin, mp_INT); +		if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin, 0))) +			return irq_trigger(idx);  	}  	/*           * nonexistent IRQs are edge default @@ -1330,95 +1516,29 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,  	}  	ioapic_register_intr(irq, cfg, attr->trigger); -	if (irq < legacy_pic->nr_legacy_irqs) +	if (irq < nr_legacy_irqs())  		legacy_pic->mask(irq);  	ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry);  } -static bool __init io_apic_pin_not_connected(int idx, int ioapic_idx, int pin) -{ -	if (idx != -1) -		return false; - -	apic_printk(APIC_VERBOSE, KERN_DEBUG " apic %d pin %d not connected\n", -		    mpc_ioapic_id(ioapic_idx), pin); -	return true; -} - -static void __init __io_apic_setup_irqs(unsigned int ioapic_idx) -{ -	int idx, node = cpu_to_node(0); -	struct io_apic_irq_attr attr; -	unsigned int pin, irq; - -	for (pin = 0; pin < ioapics[ioapic_idx].nr_registers; pin++) { -		idx = find_irq_entry(ioapic_idx, pin, mp_INT); -		if (io_apic_pin_not_connected(idx, ioapic_idx, pin)) -			continue; - -		irq = pin_2_irq(idx, ioapic_idx, pin); - -		if ((ioapic_idx > 0) && (irq > 16)) -			continue; - -		/* -		 * Skip the timer IRQ if there's a quirk handler -		 * installed and if it returns 1: -		 */ -		if (apic->multi_timer_check && -		    apic->multi_timer_check(ioapic_idx, irq)) -			continue; - -		set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx), -				     irq_polarity(idx)); - -		io_apic_setup_irq_pin(irq, node, &attr); -	} -} -  static void __init setup_IO_APIC_irqs(void)  { -	unsigned int ioapic_idx; +	unsigned int ioapic, pin; +	int idx;  	apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); -	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) -		__io_apic_setup_irqs(ioapic_idx); -} - -/* - * for the gsit that is not in first ioapic - * but could not use acpi_register_gsi() - * like some special sci in IBM x3330 - */ -void setup_IO_APIC_irq_extra(u32 gsi) -{ -	int ioapic_idx = 0, pin, idx, irq, node = cpu_to_node(0); -	struct io_apic_irq_attr attr; - -	/* -	 * Convert 'gsi' to 'ioapic.pin'. -	 */ -	ioapic_idx = mp_find_ioapic(gsi); -	if (ioapic_idx < 0) -		return; - -	pin = mp_find_ioapic_pin(ioapic_idx, gsi); -	idx = find_irq_entry(ioapic_idx, pin, mp_INT); -	if (idx == -1) -		return; - -	irq = pin_2_irq(idx, ioapic_idx, pin); - -	/* Only handle the non legacy irqs on secondary ioapics */ -	if (ioapic_idx == 0 || irq < NR_IRQS_LEGACY) -		return; - -	set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx), -			     irq_polarity(idx)); - -	io_apic_setup_irq_pin_once(irq, node, &attr); +	for_each_ioapic_pin(ioapic, pin) { +		idx = find_irq_entry(ioapic, pin, mp_INT); +		if (idx < 0) +			apic_printk(APIC_VERBOSE, +				    KERN_DEBUG " apic %d pin %d not connected\n", +				    mpc_ioapic_id(ioapic), pin); +		else +			pin_2_irq(idx, ioapic, pin, +				  ioapic ? 0 : IOAPIC_MAP_ALLOC); +	}  }  /* @@ -1586,7 +1706,7 @@ __apicdebuginit(void) print_IO_APICs(void)  	struct irq_chip *chip;  	printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); -	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) +	for_each_ioapic(ioapic_idx)  		printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",  		       mpc_ioapic_id(ioapic_idx),  		       ioapics[ioapic_idx].nr_registers); @@ -1597,7 +1717,7 @@ __apicdebuginit(void) print_IO_APICs(void)  	 */  	printk(KERN_INFO "testing the IO APIC.......................\n"); -	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) +	for_each_ioapic(ioapic_idx)  		print_IO_APIC(ioapic_idx);  	printk(KERN_DEBUG "IRQ to pin mappings:\n"); @@ -1608,7 +1728,7 @@ __apicdebuginit(void) print_IO_APICs(void)  		if (chip != &ioapic_chip)  			continue; -		cfg = irq_get_chip_data(irq); +		cfg = irq_cfg(irq);  		if (!cfg)  			continue;  		entry = cfg->irq_2_pin; @@ -1758,7 +1878,7 @@ __apicdebuginit(void) print_PIC(void)  	unsigned int v;  	unsigned long flags; -	if (!legacy_pic->nr_legacy_irqs) +	if (!nr_legacy_irqs())  		return;  	printk(KERN_DEBUG "\nprinting PIC contents\n"); @@ -1828,26 +1948,22 @@ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };  void __init enable_IO_APIC(void)  {  	int i8259_apic, i8259_pin; -	int apic; +	int apic, pin; -	if (!legacy_pic->nr_legacy_irqs) +	if (!nr_legacy_irqs())  		return; -	for(apic = 0; apic < nr_ioapics; apic++) { -		int pin; +	for_each_ioapic_pin(apic, pin) {  		/* See if any of the pins is in ExtINT mode */ -		for (pin = 0; pin < ioapics[apic].nr_registers; pin++) { -			struct IO_APIC_route_entry entry; -			entry = ioapic_read_entry(apic, pin); +		struct IO_APIC_route_entry entry = ioapic_read_entry(apic, pin); -			/* If the interrupt line is enabled and in ExtInt mode -			 * I have found the pin where the i8259 is connected. -			 */ -			if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) { -				ioapic_i8259.apic = apic; -				ioapic_i8259.pin  = pin; -				goto found_i8259; -			} +		/* If the interrupt line is enabled and in ExtInt mode +		 * I have found the pin where the i8259 is connected. +		 */ +		if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) { +			ioapic_i8259.apic = apic; +			ioapic_i8259.pin  = pin; +			goto found_i8259;  		}  	}   found_i8259: @@ -1919,7 +2035,7 @@ void disable_IO_APIC(void)  	 */  	clear_IO_APIC(); -	if (!legacy_pic->nr_legacy_irqs) +	if (!nr_legacy_irqs())  		return;  	x86_io_apic_ops.disable(); @@ -1950,7 +2066,7 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)  	/*  	 * Set the IOAPIC ID to the value stored in the MPC table.  	 */ -	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) { +	for_each_ioapic(ioapic_idx) {  		/* Read the register 0 value */  		raw_spin_lock_irqsave(&ioapic_lock, flags);  		reg_00.raw = io_apic_read(ioapic_idx, 0); @@ -2123,7 +2239,7 @@ static unsigned int startup_ioapic_irq(struct irq_data *data)  	unsigned long flags;  	raw_spin_lock_irqsave(&ioapic_lock, flags); -	if (irq < legacy_pic->nr_legacy_irqs) { +	if (irq < nr_legacy_irqs()) {  		legacy_pic->mask(irq);  		if (legacy_pic->irq_pending(irq))  			was_pending = 1; @@ -2225,7 +2341,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)  			apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);  			goto unlock;  		} -		__this_cpu_write(vector_irq[vector], -1); +		__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);  unlock:  		raw_spin_unlock(&desc->lock);  	} @@ -2253,7 +2369,7 @@ static void irq_complete_move(struct irq_cfg *cfg)  void irq_force_complete_move(int irq)  { -	struct irq_cfg *cfg = irq_get_chip_data(irq); +	struct irq_cfg *cfg = irq_cfg(irq);  	if (!cfg)  		return; @@ -2514,26 +2630,15 @@ static inline void init_IO_APIC_traps(void)  	struct irq_cfg *cfg;  	unsigned int irq; -	/* -	 * NOTE! The local APIC isn't very good at handling -	 * multiple interrupts at the same interrupt level. -	 * As the interrupt level is determined by taking the -	 * vector number and shifting that right by 4, we -	 * want to spread these out a bit so that they don't -	 * all fall in the same interrupt level. -	 * -	 * Also, we've got to be careful not to trash gate -	 * 0x80, because int 0x80 is hm, kind of importantish. ;) -	 */  	for_each_active_irq(irq) { -		cfg = irq_get_chip_data(irq); +		cfg = irq_cfg(irq);  		if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {  			/*  			 * Hmm.. We don't have an entry for this,  			 * so default to an old-fashioned 8259  			 * interrupt if we can..  			 */ -			if (irq < legacy_pic->nr_legacy_irqs) +			if (irq < nr_legacy_irqs())  				legacy_pic->make_irq(irq);  			else  				/* Strange. Oh, well.. */ @@ -2649,8 +2754,6 @@ static int __init disable_timer_pin_setup(char *arg)  }  early_param("disable_timer_pin_1", disable_timer_pin_setup); -int timer_through_8259 __initdata; -  /*   * This code may look a bit paranoid, but it's supposed to cooperate with   * a wide range of boards and BIOS bugs.  Fortunately only the timer IRQ @@ -2661,7 +2764,7 @@ int timer_through_8259 __initdata;   */  static inline void __init check_timer(void)  { -	struct irq_cfg *cfg = irq_get_chip_data(0); +	struct irq_cfg *cfg = irq_cfg(0);  	int node = cpu_to_node(0);  	int apic1, pin1, apic2, pin2;  	unsigned long flags; @@ -2755,7 +2858,6 @@ static inline void __init check_timer(void)  		legacy_pic->unmask(0);  		if (timer_irq_works()) {  			apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); -			timer_through_8259 = 1;  			goto out;  		}  		/* @@ -2827,15 +2929,54 @@ out:   */  #define PIC_IRQS	(1UL << PIC_CASCADE_IR) +static int mp_irqdomain_create(int ioapic) +{ +	size_t size; +	int hwirqs = mp_ioapic_pin_count(ioapic); +	struct ioapic *ip = &ioapics[ioapic]; +	struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg; +	struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic); + +	size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(ioapic); +	ip->pin_info = kzalloc(size, GFP_KERNEL); +	if (!ip->pin_info) +		return -ENOMEM; + +	if (cfg->type == IOAPIC_DOMAIN_INVALID) +		return 0; + +	ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops, +					      (void *)(long)ioapic); +	if(!ip->irqdomain) { +		kfree(ip->pin_info); +		ip->pin_info = NULL; +		return -ENOMEM; +	} + +	if (cfg->type == IOAPIC_DOMAIN_LEGACY || +	    cfg->type == IOAPIC_DOMAIN_STRICT) +		ioapic_dynirq_base = max(ioapic_dynirq_base, +					 gsi_cfg->gsi_end + 1); + +	if (gsi_cfg->gsi_base == 0) +		irq_set_default_host(ip->irqdomain); + +	return 0; +} +  void __init setup_IO_APIC(void)  { +	int ioapic;  	/*  	 * calling enable_IO_APIC() is moved to setup_local_APIC for BP  	 */ -	io_apic_irqs = legacy_pic->nr_legacy_irqs ? ~PIC_IRQS : ~0UL; +	io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL;  	apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); +	for_each_ioapic(ioapic) +		BUG_ON(mp_irqdomain_create(ioapic)); +  	/*           * Set up IO-APIC IRQ routing.           */ @@ -2844,8 +2985,10 @@ void __init setup_IO_APIC(void)  	sync_Arb_IDs();  	setup_IO_APIC_irqs();  	init_IO_APIC_traps(); -	if (legacy_pic->nr_legacy_irqs) +	if (nr_legacy_irqs())  		check_timer(); + +	ioapic_initialized = 1;  }  /* @@ -2880,7 +3023,7 @@ static void ioapic_resume(void)  {  	int ioapic_idx; -	for (ioapic_idx = nr_ioapics - 1; ioapic_idx >= 0; ioapic_idx--) +	for_each_ioapic_reverse(ioapic_idx)  		resume_ioapic_id(ioapic_idx);  	restore_ioapic_entries(); @@ -2926,7 +3069,7 @@ int arch_setup_hwirq(unsigned int irq, int node)  void arch_teardown_hwirq(unsigned int irq)  { -	struct irq_cfg *cfg = irq_get_chip_data(irq); +	struct irq_cfg *cfg = irq_cfg(irq);  	unsigned long flags;  	free_remapped_irq(irq); @@ -3053,7 +3196,7 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,  	if (!irq_offset)  		write_msi_msg(irq, &msg); -	setup_remapped_irq(irq, irq_get_chip_data(irq), chip); +	setup_remapped_irq(irq, irq_cfg(irq), chip);  	irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); @@ -3192,7 +3335,7 @@ int default_setup_hpet_msi(unsigned int irq, unsigned int id)  	hpet_msi_write(irq_get_handler_data(irq), &msg);  	irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); -	setup_remapped_irq(irq, irq_get_chip_data(irq), chip); +	setup_remapped_irq(irq, irq_cfg(irq), chip);  	irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");  	return 0; @@ -3303,27 +3446,6 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)  	return ret;  } -int io_apic_setup_irq_pin_once(unsigned int irq, int node, -			       struct io_apic_irq_attr *attr) -{ -	unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin; -	int ret; -	struct IO_APIC_route_entry orig_entry; - -	/* Avoid redundant programming */ -	if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) { -		pr_debug("Pin %d-%d already programmed\n", mpc_ioapic_id(ioapic_idx), pin); -		orig_entry = ioapic_read_entry(attr->ioapic, pin); -		if (attr->trigger == orig_entry.trigger && attr->polarity == orig_entry.polarity) -			return 0; -		return -EBUSY; -	} -	ret = io_apic_setup_irq_pin(irq, node, attr); -	if (!ret) -		set_bit(pin, ioapics[ioapic_idx].pin_programmed); -	return ret; -} -  static int __init io_apic_get_redir_entries(int ioapic)  {  	union IO_APIC_reg_01	reg_01; @@ -3340,20 +3462,13 @@ static int __init io_apic_get_redir_entries(int ioapic)  	return reg_01.bits.entries + 1;  } -static void __init probe_nr_irqs_gsi(void) -{ -	int nr; - -	nr = gsi_top + NR_IRQS_LEGACY; -	if (nr > nr_irqs_gsi) -		nr_irqs_gsi = nr; - -	printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi); -} -  unsigned int arch_dynirq_lower_bound(unsigned int from)  { -	return from < nr_irqs_gsi ? nr_irqs_gsi : from; +	/* +	 * dmar_alloc_hwirq() may be called before setup_IO_APIC(), so use +	 * gsi_top if ioapic_dynirq_base hasn't been initialized yet. +	 */ +	return ioapic_initialized ? ioapic_dynirq_base : gsi_top;  }  int __init arch_probe_nr_irqs(void) @@ -3363,33 +3478,17 @@ int __init arch_probe_nr_irqs(void)  	if (nr_irqs > (NR_VECTORS * nr_cpu_ids))  		nr_irqs = NR_VECTORS * nr_cpu_ids; -	nr = nr_irqs_gsi + 8 * nr_cpu_ids; +	nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids;  #if defined(CONFIG_PCI_MSI) || defined(CONFIG_HT_IRQ)  	/*  	 * for MSI and HT dyn irq  	 */ -	nr += nr_irqs_gsi * 16; +	nr += gsi_top * 16;  #endif  	if (nr < nr_irqs)  		nr_irqs = nr; -	return NR_IRQS_LEGACY; -} - -int io_apic_set_pci_routing(struct device *dev, int irq, -			    struct io_apic_irq_attr *irq_attr) -{ -	int node; - -	if (!IO_APIC_IRQ(irq)) { -		apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", -			    irq_attr->ioapic); -		return -EINVAL; -	} - -	node = dev ? dev_to_node(dev) : cpu_to_node(0); - -	return io_apic_setup_irq_pin_once(irq, node, irq_attr); +	return 0;  }  #ifdef CONFIG_X86_32 @@ -3483,9 +3582,8 @@ static u8 __init io_apic_unique_id(u8 id)  	DECLARE_BITMAP(used, 256);  	bitmap_zero(used, 256); -	for (i = 0; i < nr_ioapics; i++) { +	for_each_ioapic(i)  		__set_bit(mpc_ioapic_id(i), used); -	}  	if (!test_bit(id, used))  		return id;  	return find_first_zero_bit(used, 256); @@ -3543,14 +3641,13 @@ void __init setup_ioapic_dest(void)  	if (skip_ioapic_setup == 1)  		return; -	for (ioapic = 0; ioapic < nr_ioapics; ioapic++) -	for (pin = 0; pin < ioapics[ioapic].nr_registers; pin++) { +	for_each_ioapic_pin(ioapic, pin) {  		irq_entry = find_irq_entry(ioapic, pin, mp_INT);  		if (irq_entry == -1)  			continue; -		irq = pin_2_irq(irq_entry, ioapic, pin); -		if ((ioapic > 0) && (irq > 16)) +		irq = pin_2_irq(irq_entry, ioapic, pin, 0); +		if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq))  			continue;  		idata = irq_get_irq_data(irq); @@ -3573,29 +3670,33 @@ void __init setup_ioapic_dest(void)  static struct resource *ioapic_resources; -static struct resource * __init ioapic_setup_resources(int nr_ioapics) +static struct resource * __init ioapic_setup_resources(void)  {  	unsigned long n;  	struct resource *res;  	char *mem; -	int i; +	int i, num = 0; -	if (nr_ioapics <= 0) +	for_each_ioapic(i) +		num++; +	if (num == 0)  		return NULL;  	n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource); -	n *= nr_ioapics; +	n *= num;  	mem = alloc_bootmem(n);  	res = (void *)mem; -	mem += sizeof(struct resource) * nr_ioapics; +	mem += sizeof(struct resource) * num; -	for (i = 0; i < nr_ioapics; i++) { -		res[i].name = mem; -		res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; +	num = 0; +	for_each_ioapic(i) { +		res[num].name = mem; +		res[num].flags = IORESOURCE_MEM | IORESOURCE_BUSY;  		snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);  		mem += IOAPIC_RESOURCE_NAME_SIZE; +		num++;  	}  	ioapic_resources = res; @@ -3609,8 +3710,8 @@ void __init native_io_apic_init_mappings(void)  	struct resource *ioapic_res;  	int i; -	ioapic_res = ioapic_setup_resources(nr_ioapics); -	for (i = 0; i < nr_ioapics; i++) { +	ioapic_res = ioapic_setup_resources(); +	for_each_ioapic(i) {  		if (smp_found_config) {  			ioapic_phys = mpc_ioapic_addr(i);  #ifdef CONFIG_X86_32 @@ -3641,8 +3742,6 @@ fake_ioapic_page:  		ioapic_res->end = ioapic_phys + IO_APIC_SLOT_SIZE - 1;  		ioapic_res++;  	} - -	probe_nr_irqs_gsi();  }  void __init ioapic_insert_resources(void) @@ -3657,7 +3756,7 @@ void __init ioapic_insert_resources(void)  		return;  	} -	for (i = 0; i < nr_ioapics; i++) { +	for_each_ioapic(i) {  		insert_resource(&iomem_resource, r);  		r++;  	} @@ -3665,16 +3764,15 @@ void __init ioapic_insert_resources(void)  int mp_find_ioapic(u32 gsi)  { -	int i = 0; +	int i;  	if (nr_ioapics == 0)  		return -1;  	/* Find the IOAPIC that manages this GSI. */ -	for (i = 0; i < nr_ioapics; i++) { +	for_each_ioapic(i) {  		struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(i); -		if ((gsi >= gsi_cfg->gsi_base) -		    && (gsi <= gsi_cfg->gsi_end)) +		if (gsi >= gsi_cfg->gsi_base && gsi <= gsi_cfg->gsi_end)  			return i;  	} @@ -3686,7 +3784,7 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)  {  	struct mp_ioapic_gsi *gsi_cfg; -	if (WARN_ON(ioapic == -1)) +	if (WARN_ON(ioapic < 0))  		return -1;  	gsi_cfg = mp_ioapic_gsi_routing(ioapic); @@ -3729,7 +3827,8 @@ static __init int bad_ioapic_register(int idx)  	return 0;  } -void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) +void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, +			       struct ioapic_domain_cfg *cfg)  {  	int idx = 0;  	int entries; @@ -3743,6 +3842,8 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)  	ioapics[idx].mp_config.type = MP_IOAPIC;  	ioapics[idx].mp_config.flags = MPC_APIC_USABLE;  	ioapics[idx].mp_config.apicaddr = address; +	ioapics[idx].irqdomain = NULL; +	ioapics[idx].irqdomain_cfg = *cfg;  	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); @@ -3779,6 +3880,97 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)  	nr_ioapics++;  } +int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, +		     irq_hw_number_t hwirq) +{ +	int ioapic = (int)(long)domain->host_data; +	struct mp_pin_info *info = mp_pin_info(ioapic, hwirq); +	struct io_apic_irq_attr attr; + +	/* Get default attribute if not set by caller yet */ +	if (!info->set) { +		u32 gsi = mp_pin_to_gsi(ioapic, hwirq); + +		if (acpi_get_override_irq(gsi, &info->trigger, +					  &info->polarity) < 0) { +			/* +			 * PCI interrupts are always polarity one level +			 * triggered. +			 */ +			info->trigger = 1; +			info->polarity = 1; +		} +		info->node = NUMA_NO_NODE; + +		/* +		 * setup_IO_APIC_irqs() programs all legacy IRQs with default +		 * trigger and polarity attributes. Don't set the flag for that +		 * case so the first legacy IRQ user could reprogram the pin +		 * with real trigger and polarity attributes. +		 */ +		if (virq >= nr_legacy_irqs() || info->count) +			info->set = 1; +	} +	set_io_apic_irq_attr(&attr, ioapic, hwirq, info->trigger, +			     info->polarity); + +	return io_apic_setup_irq_pin(virq, info->node, &attr); +} + +void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq) +{ +	struct irq_data *data = irq_get_irq_data(virq); +	struct irq_cfg *cfg = irq_cfg(virq); +	int ioapic = (int)(long)domain->host_data; +	int pin = (int)data->hwirq; + +	ioapic_mask_entry(ioapic, pin); +	__remove_pin_from_irq(cfg, ioapic, pin); +	WARN_ON(cfg->irq_2_pin != NULL); +	arch_teardown_hwirq(virq); +} + +int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node) +{ +	int ret = 0; +	int ioapic, pin; +	struct mp_pin_info *info; + +	ioapic = mp_find_ioapic(gsi); +	if (ioapic < 0) +		return -ENODEV; + +	pin = mp_find_ioapic_pin(ioapic, gsi); +	info = mp_pin_info(ioapic, pin); +	trigger = trigger ? 1 : 0; +	polarity = polarity ? 1 : 0; + +	mutex_lock(&ioapic_mutex); +	if (!info->set) { +		info->trigger = trigger; +		info->polarity = polarity; +		info->node = node; +		info->set = 1; +	} else if (info->trigger != trigger || info->polarity != polarity) { +		ret = -EBUSY; +	} +	mutex_unlock(&ioapic_mutex); + +	return ret; +} + +bool mp_should_keep_irq(struct device *dev) +{ +	if (dev->power.is_prepared) +		return true; +#ifdef	CONFIG_PM_RUNTIME +	if (dev->power.runtime_status == RPM_SUSPENDING) +		return true; +#endif + +	return false; +} +  /* Enable IOAPIC early just for system timer */  void __init pre_init_apic_IRQ0(void)  {  |