diff options
Diffstat (limited to 'arch/powerpc/platforms/iseries/irq.c')
| -rw-r--r-- | arch/powerpc/platforms/iseries/irq.c | 396 | 
1 files changed, 0 insertions, 396 deletions
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c deleted file mode 100644 index ba446bf355a..00000000000 --- a/arch/powerpc/platforms/iseries/irq.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * This module supports the iSeries PCI bus interrupt handling - * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp> - * Copyright (C) 2004-2005 IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, - * Boston, MA  02111-1307  USA - * - * Change Activity: - *   Created, December 13, 2000 by Wayne Holm - * End Change Activity - */ -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/irq.h> -#include <linux/spinlock.h> - -#include <asm/paca.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> - -#include "irq.h" -#include "pci.h" -#include "call_pci.h" -#include "smp.h" - -#ifdef CONFIG_PCI - -enum pci_event_type { -	pe_bus_created		= 0,	/* PHB has been created */ -	pe_bus_error		= 1,	/* PHB has failed */ -	pe_bus_failed		= 2,	/* Msg to Secondary, Primary failed bus */ -	pe_node_failed		= 4,	/* Multi-adapter bridge has failed */ -	pe_node_recovered	= 5,	/* Multi-adapter bridge has recovered */ -	pe_bus_recovered	= 12,	/* PHB has been recovered */ -	pe_unquiese_bus		= 18,	/* Secondary bus unqiescing */ -	pe_bridge_error		= 21,	/* Bridge Error */ -	pe_slot_interrupt	= 22	/* Slot interrupt */ -}; - -struct pci_event { -	struct HvLpEvent event; -	union { -		u64 __align;		/* Align on an 8-byte boundary */ -		struct { -			u32		fisr; -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -			HvAgentId	dev_id; -		} slot; -		struct { -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -		} bus; -		struct { -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -			HvAgentId	dev_id; -		} node; -	} data; -}; - -static DEFINE_SPINLOCK(pending_irqs_lock); -static int num_pending_irqs; -static int pending_irqs[NR_IRQS]; - -static void int_received(struct pci_event *event) -{ -	int irq; - -	switch (event->event.xSubtype) { -	case pe_slot_interrupt: -		irq = event->event.xCorrelationToken; -		if (irq < NR_IRQS) { -			spin_lock(&pending_irqs_lock); -			pending_irqs[irq]++; -			num_pending_irqs++; -			spin_unlock(&pending_irqs_lock); -		} else { -			printk(KERN_WARNING "int_received: bad irq number %d\n", -					irq); -			HvCallPci_eoi(event->data.slot.bus_number, -					event->data.slot.sub_bus_number, -					event->data.slot.dev_id); -		} -		break; -		/* Ignore error recovery events for now */ -	case pe_bus_created: -		printk(KERN_INFO "int_received: system bus %d created\n", -			event->data.bus.bus_number); -		break; -	case pe_bus_error: -	case pe_bus_failed: -		printk(KERN_INFO "int_received: system bus %d failed\n", -			event->data.bus.bus_number); -		break; -	case pe_bus_recovered: -	case pe_unquiese_bus: -		printk(KERN_INFO "int_received: system bus %d recovered\n", -			event->data.bus.bus_number); -		break; -	case pe_node_failed: -	case pe_bridge_error: -		printk(KERN_INFO -			"int_received: multi-adapter bridge %d/%d/%d failed\n", -			event->data.node.bus_number, -			event->data.node.sub_bus_number, -			event->data.node.dev_id); -		break; -	case pe_node_recovered: -		printk(KERN_INFO -			"int_received: multi-adapter bridge %d/%d/%d recovered\n", -			event->data.node.bus_number, -			event->data.node.sub_bus_number, -			event->data.node.dev_id); -		break; -	default: -		printk(KERN_ERR -			"int_received: unrecognized event subtype 0x%x\n", -			event->event.xSubtype); -		break; -	} -} - -static void pci_event_handler(struct HvLpEvent *event) -{ -	if (event && (event->xType == HvLpEvent_Type_PciIo)) { -		if (hvlpevent_is_int(event)) -			int_received((struct pci_event *)event); -		else -			printk(KERN_ERR -				"pci_event_handler: unexpected ack received\n"); -	} else if (event) -		printk(KERN_ERR -			"pci_event_handler: Unrecognized PCI event type 0x%x\n", -			(int)event->xType); -	else -		printk(KERN_ERR "pci_event_handler: NULL event received\n"); -} - -#define REAL_IRQ_TO_SUBBUS(irq)	(((irq) >> 14) & 0xff) -#define REAL_IRQ_TO_BUS(irq)	((((irq) >> 6) & 0xff) + 1) -#define REAL_IRQ_TO_IDSEL(irq)	((((irq) >> 3) & 7) + 1) -#define REAL_IRQ_TO_FUNC(irq)	((irq) & 7) - -/* - * This will be called by device drivers (via enable_IRQ) - * to enable INTA in the bridge interrupt status register. - */ -static void iseries_enable_IRQ(unsigned int irq) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irq_map[irq].hwirq; - -	/* The IRQ has already been locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Unmask secondary INTA */ -	mask = 0x80000000; -	HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); -} - -/* This is called by iseries_activate_IRQs */ -static unsigned int iseries_startup_IRQ(unsigned int irq) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irq_map[irq].hwirq; - -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Link the IRQ number to the bridge */ -	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq); - -	/* Unmask bridge interrupts in the FISR */ -	mask = 0x01010000 << function; -	HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); -	iseries_enable_IRQ(irq); -	return 0; -} - -/* - * This is called out of iSeries_fixup to activate interrupt - * generation for usable slots - */ -void __init iSeries_activate_IRQs() -{ -	int irq; -	unsigned long flags; - -	for_each_irq (irq) { -		struct irq_desc *desc = irq_to_desc(irq); - -		if (desc && desc->chip && desc->chip->startup) { -			raw_spin_lock_irqsave(&desc->lock, flags); -			desc->chip->startup(irq); -			raw_spin_unlock_irqrestore(&desc->lock, flags); -		} -	} -} - -/*  this is not called anywhere currently */ -static void iseries_shutdown_IRQ(unsigned int irq) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irq_map[irq].hwirq; - -	/* irq should be locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Invalidate the IRQ number in the bridge */ -	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); - -	/* Mask bridge interrupts in the FISR */ -	mask = 0x01010000 << function; -	HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); -} - -/* - * This will be called by device drivers (via disable_IRQ) - * to disable INTA in the bridge interrupt status register. - */ -static void iseries_disable_IRQ(unsigned int irq) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irq_map[irq].hwirq; - -	/* The IRQ has already been locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Mask secondary INTA   */ -	mask = 0x80000000; -	HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); -} - -static void iseries_end_IRQ(unsigned int irq) -{ -	unsigned int rirq = (unsigned int)irq_map[irq].hwirq; - -	HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), -		(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); -} - -static struct irq_chip iseries_pic = { -	.name		= "iSeries", -	.startup	= iseries_startup_IRQ, -	.shutdown	= iseries_shutdown_IRQ, -	.unmask		= iseries_enable_IRQ, -	.mask		= iseries_disable_IRQ, -	.eoi		= iseries_end_IRQ -}; - -/* - * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot - * It calculates the irq value for the slot. - * Note that sub_bus is always 0 (at the moment at least). - */ -int __init iSeries_allocate_IRQ(HvBusNumber bus, -		HvSubBusNumber sub_bus, u32 bsubbus) -{ -	unsigned int realirq; -	u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); -	u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); - -	realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) -		+ function; - -	return irq_create_mapping(NULL, realirq); -} - -#endif /* CONFIG_PCI */ - -/* - * Get the next pending IRQ. - */ -unsigned int iSeries_get_irq(void) -{ -	int irq = NO_IRQ_IGNORE; - -#ifdef CONFIG_SMP -	if (get_lppaca()->int_dword.fields.ipi_cnt) { -		get_lppaca()->int_dword.fields.ipi_cnt = 0; -		iSeries_smp_message_recv(); -	} -#endif /* CONFIG_SMP */ -	if (hvlpevent_is_pending()) -		process_hvlpevents(); - -#ifdef CONFIG_PCI -	if (num_pending_irqs) { -		spin_lock(&pending_irqs_lock); -		for (irq = 0; irq < NR_IRQS; irq++) { -			if (pending_irqs[irq]) { -				pending_irqs[irq]--; -				num_pending_irqs--; -				break; -			} -		} -		spin_unlock(&pending_irqs_lock); -		if (irq >= NR_IRQS) -			irq = NO_IRQ_IGNORE; -	} -#endif - -	return irq; -} - -#ifdef CONFIG_PCI - -static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, -				irq_hw_number_t hw) -{ -	set_irq_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); - -	return 0; -} - -static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) -{ -	/* Match all */ -	return 1; -} - -static struct irq_host_ops iseries_irq_host_ops = { -	.map = iseries_irq_host_map, -	.match = iseries_irq_host_match, -}; - -/* - * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c - * It must be called before the bus walk. - */ -void __init iSeries_init_IRQ(void) -{ -	/* Register PCI event handler and open an event path */ -	struct irq_host *host; -	int ret; - -	/* -	 * The Hypervisor only allows us up to 256 interrupt -	 * sources (the irq number is passed in a u8). -	 */ -	irq_set_virq_count(256); - -	/* Create irq host. No need for a revmap since HV will give us -	 * back our virtual irq number -	 */ -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -			      &iseries_irq_host_ops, 0); -	BUG_ON(host == NULL); -	irq_set_default_host(host); - -	ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, -			&pci_event_handler); -	if (ret == 0) { -		ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); -		if (ret != 0) -			printk(KERN_ERR "iseries_init_IRQ: open event path " -					"failed with rc 0x%x\n", ret); -	} else -		printk(KERN_ERR "iseries_init_IRQ: register handler " -				"failed with rc 0x%x\n", ret); -} - -#endif	/* CONFIG_PCI */  | 
