| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * MSI hooks for standard x86 apic | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | #include <linux/irq.h>
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | #include <linux/msi.h>
 | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | #include <linux/dmar.h>
 | 
					
						
							| 
									
										
										
										
											2006-06-26 14:00:02 +02:00
										 |  |  | #include <asm/smp.h>
 | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | #include <asm/msidef.h>
 | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | static struct irq_chip	ia64_msi_chip; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | #ifdef CONFIG_SMP
 | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | static int ia64_set_msi_irq_affinity(unsigned int irq, | 
					
						
							| 
									
										
										
										
											2008-12-13 21:20:26 +10:30
										 |  |  | 				      const cpumask_t *cpu_mask) | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	struct msi_msg msg; | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:48 +09:00
										 |  |  | 	u32 addr, data; | 
					
						
							| 
									
										
										
										
											2008-12-13 21:20:26 +10:30
										 |  |  | 	int cpu = first_cpu(*cpu_mask); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:48 +09:00
										 |  |  | 	if (!cpu_online(cpu)) | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:48 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 14:32:22 +09:00
										 |  |  | 	if (irq_prepare_move(irq, cpu)) | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:33 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	read_msi_msg(irq, &msg); | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	addr = msg.address_lo; | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 	addr &= MSI_ADDR_DEST_ID_MASK; | 
					
						
							|  |  |  | 	addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu)); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	msg.address_lo = addr; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:48 +09:00
										 |  |  | 	data = msg.data; | 
					
						
							|  |  |  | 	data &= MSI_DATA_VECTOR_MASK; | 
					
						
							|  |  |  | 	data |= MSI_DATA_VECTOR(irq_to_vector(irq)); | 
					
						
							|  |  |  | 	msg.data = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	write_msi_msg(irq, &msg); | 
					
						
							| 
									
										
										
										
											2009-01-12 15:27:13 -08:00
										 |  |  | 	cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu)); | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | #endif /* CONFIG_SMP */
 | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	struct msi_msg	msg; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 	unsigned long	dest_phys_id; | 
					
						
							| 
									
										
										
										
											2007-03-26 09:38:42 +09:00
										 |  |  | 	int	irq, vector; | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:33 +09:00
										 |  |  | 	cpumask_t mask; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | 	irq = create_irq(); | 
					
						
							|  |  |  | 	if (irq < 0) | 
					
						
							|  |  |  | 		return irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	set_irq_msi(irq, desc); | 
					
						
							| 
									
										
										
										
											2007-07-17 21:22:33 +09:00
										 |  |  | 	cpus_and(mask, irq_to_domain(irq), cpu_online_map); | 
					
						
							|  |  |  | 	dest_phys_id = cpu_physical_id(first_cpu(mask)); | 
					
						
							| 
									
										
										
										
											2007-04-06 16:51:12 +09:00
										 |  |  | 	vector = irq_to_vector(irq); | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	msg.address_hi = 0; | 
					
						
							|  |  |  | 	msg.address_lo = | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:34 -07:00
										 |  |  | 		MSI_ADDR_HEADER | | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 		MSI_ADDR_DEST_MODE_PHYS | | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:34 -07:00
										 |  |  | 		MSI_ADDR_REDIRECTION_CPU | | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 		MSI_ADDR_DEST_ID_CPU(dest_phys_id); | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	msg.data = | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:34 -07:00
										 |  |  | 		MSI_DATA_TRIGGER_EDGE | | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | 		MSI_DATA_LEVEL_ASSERT | | 
					
						
							|  |  |  | 		MSI_DATA_DELIVERY_FIXED | | 
					
						
							|  |  |  | 		MSI_DATA_VECTOR(vector); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	write_msi_msg(irq, &msg); | 
					
						
							|  |  |  | 	set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-30 16:01:49 +09:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | void ia64_teardown_msi_irq(unsigned int irq) | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | 	destroy_irq(irq); | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | static void ia64_ack_msi_irq(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-25 14:32:22 +09:00
										 |  |  | 	irq_complete_move(irq); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	move_native_irq(irq); | 
					
						
							|  |  |  | 	ia64_eoi(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ia64_msi_retrigger_irq(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-04-06 16:51:12 +09:00
										 |  |  | 	unsigned int vector = irq_to_vector(irq); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 	ia64_resend_irq(vector); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  |  * Generic ops used on most IA64 platforms. | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | static struct irq_chip ia64_msi_chip = { | 
					
						
							|  |  |  | 	.name		= "PCI-MSI", | 
					
						
							|  |  |  | 	.mask		= mask_msi_irq, | 
					
						
							|  |  |  | 	.unmask		= unmask_msi_irq, | 
					
						
							|  |  |  | 	.ack		= ia64_ack_msi_irq, | 
					
						
							|  |  |  | #ifdef CONFIG_SMP
 | 
					
						
							|  |  |  | 	.set_affinity	= ia64_set_msi_irq_affinity, | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	.retrigger	= ia64_msi_retrigger_irq, | 
					
						
							| 
									
										
										
										
											2006-04-10 21:17:48 -05:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (platform_setup_msi_irq) | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | 		return platform_setup_msi_irq(pdev, desc); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-28 12:56:37 -07:00
										 |  |  | 	return ia64_setup_msi_irq(pdev, desc); | 
					
						
							| 
									
										
										
										
											2006-10-04 02:16:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void arch_teardown_msi_irq(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (platform_teardown_msi_irq) | 
					
						
							|  |  |  | 		return platform_teardown_msi_irq(irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ia64_teardown_msi_irq(irq); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_DMAR
 | 
					
						
							|  |  |  | #ifdef CONFIG_SMP
 | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct irq_cfg *cfg = irq_cfg + irq; | 
					
						
							|  |  |  | 	struct msi_msg msg; | 
					
						
							| 
									
										
										
										
											2008-12-13 21:20:26 +10:30
										 |  |  | 	int cpu = cpumask_first(mask); | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!cpu_online(cpu)) | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (irq_prepare_move(irq, cpu)) | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dmar_msi_read(irq, &msg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msg.data &= ~MSI_DATA_VECTOR_MASK; | 
					
						
							|  |  |  | 	msg.data |= MSI_DATA_VECTOR(cfg->vector); | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | 
					
						
							|  |  |  | 	msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu)); | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dmar_msi_write(irq, &msg); | 
					
						
							| 
									
										
										
										
											2009-01-12 15:27:13 -08:00
										 |  |  | 	cpumask_copy(irq_desc[irq].affinity, mask); | 
					
						
							| 
									
										
										
										
											2009-04-27 17:59:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | #endif /* CONFIG_SMP */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-10 12:45:01 -07:00
										 |  |  | static struct irq_chip dmar_msi_type = { | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 	.name = "DMAR_MSI", | 
					
						
							|  |  |  | 	.unmask = dmar_msi_unmask, | 
					
						
							|  |  |  | 	.mask = dmar_msi_mask, | 
					
						
							|  |  |  | 	.ack = ia64_ack_msi_irq, | 
					
						
							|  |  |  | #ifdef CONFIG_SMP
 | 
					
						
							|  |  |  | 	.set_affinity = dmar_msi_set_affinity, | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	.retrigger = ia64_msi_retrigger_irq, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct irq_cfg *cfg = irq_cfg + irq; | 
					
						
							|  |  |  | 	unsigned dest; | 
					
						
							|  |  |  | 	cpumask_t mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpus_and(mask, irq_to_domain(irq), cpu_online_map); | 
					
						
							|  |  |  | 	dest = cpu_physical_id(first_cpu(mask)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msg->address_hi = 0; | 
					
						
							|  |  |  | 	msg->address_lo = | 
					
						
							|  |  |  | 		MSI_ADDR_HEADER | | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 		MSI_ADDR_DEST_MODE_PHYS | | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 		MSI_ADDR_REDIRECTION_CPU | | 
					
						
							| 
									
										
										
										
											2009-02-16 15:14:48 +08:00
										 |  |  | 		MSI_ADDR_DEST_ID_CPU(dest); | 
					
						
							| 
									
										
										
										
											2008-10-17 12:14:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	msg->data = | 
					
						
							|  |  |  | 		MSI_DATA_TRIGGER_EDGE | | 
					
						
							|  |  |  | 		MSI_DATA_LEVEL_ASSERT | | 
					
						
							|  |  |  | 		MSI_DATA_DELIVERY_FIXED | | 
					
						
							|  |  |  | 		MSI_DATA_VECTOR(cfg->vector); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int arch_setup_dmar_msi(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	struct msi_msg msg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = msi_compose_msg(NULL, irq, &msg); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	dmar_msi_write(irq, &msg); | 
					
						
							|  |  |  | 	set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, | 
					
						
							|  |  |  | 		"edge"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* CONFIG_DMAR */
 | 
					
						
							|  |  |  | 
 |