⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ml_sn_intr.c

📁 microwindows移植到S3C44B0的源码
💻 C
字号:
/* $Id: ml_SN_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved. *//* * intr.c- *	This file contains all of the routines necessary to set up and *	handle interrupts on an IPXX board. */#ident  "$Revision: 1.1 $"#include <linux/types.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/smp.h>#include <asm/irq.h>#include <asm/hw_irq.h>#include <asm/sn/sgi.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/io.h>#include <asm/sn/sn_private.h>#include <asm/sn/klconfig.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/xtalk/xtalk.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/intr.h>#include <asm/sn/sn2/shub_mmr_t.h>#include <asm/sal.h>#include <asm/sn/sn_sal.h>extern irqpda_t	*irqpdaindr[];extern cnodeid_t master_node_get(devfs_handle_t vhdl);extern nasid_t master_nasid;//  Initialize some shub registers for interrupts, both IO and error.voidintr_init_vecblk( nodepda_t *npda,		cnodeid_t node,		int sn){	int 			nasid = cnodeid_to_nasid(node);	nasid_t			console_nasid;	sh_ii_int0_config_u_t	ii_int_config;	cpuid_t			cpu;	cpuid_t			cpu0, cpu1;	nodepda_t		*lnodepda;	sh_ii_int0_enable_u_t	ii_int_enable;	sh_local_int0_config_u_t	local_int_config;	sh_local_int0_enable_u_t	local_int_enable;	sh_fsb_system_agent_config_u_t	fsb_system_agent;	sh_int_node_id_config_u_t	node_id_config;	int is_console;	console_nasid = get_console_nasid();	if (console_nasid < 0) {		console_nasid = master_nasid;	}	is_console = nasid == console_nasid;	if (is_headless_node(node) ) {		int cnode;		struct ia64_sal_retval ret_stuff;		// retarget all interrupts on this node to the master node.		node_id_config.sh_int_node_id_config_regval = 0;		node_id_config.sh_int_node_id_config_s.node_id = master_nasid;		node_id_config.sh_int_node_id_config_s.id_sel = 1;		HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_INT_NODE_ID_CONFIG),			node_id_config.sh_int_node_id_config_regval);		cnode = nasid_to_cnodeid(master_nasid);		lnodepda = NODEPDA(cnode);		cpu = lnodepda->node_first_cpu;		cpu = cpu_physical_id(cpu);		SAL_CALL(ret_stuff, SN_SAL_REGISTER_CE, nasid, cpu, master_nasid,0,0,0,0);		if (ret_stuff.status < 0) {			printk("%s: SN_SAL_REGISTER_CE SAL_CALL failed\n",__FUNCTION__);		}	} else {		lnodepda = NODEPDA(node);		cpu = lnodepda->node_first_cpu;		cpu = cpu_physical_id(cpu);	}	// Get the physical id's of the cpu's on this node.	cpu0 = id_eid_to_cpu_physical_id(nasid, 0);	cpu1 = id_eid_to_cpu_physical_id(nasid, 1);	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0);	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0);	// The II_INT_CONFIG register for cpu 0.	ii_int_config.sh_ii_int0_config_s.type = 0;	ii_int_config.sh_ii_int0_config_s.agt = 0;	ii_int_config.sh_ii_int0_config_s.pid = cpu0;	ii_int_config.sh_ii_int0_config_s.base = 0;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG),		ii_int_config.sh_ii_int0_config_regval);	// The II_INT_CONFIG register for cpu 1.	ii_int_config.sh_ii_int0_config_s.type = 0;	ii_int_config.sh_ii_int0_config_s.agt = 0;	ii_int_config.sh_ii_int0_config_s.pid = cpu1;	ii_int_config.sh_ii_int0_config_s.base = 0;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG),		ii_int_config.sh_ii_int0_config_regval);	// Enable interrupts for II_INT0 and 1.	ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE),		ii_int_enable.sh_ii_int0_enable_regval);	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE),		ii_int_enable.sh_ii_int0_enable_regval);	// init error regs	// LOCAL_INT0 is for the UART only.	local_int_config.sh_local_int0_config_s.type = 0;	local_int_config.sh_local_int0_config_s.agt = 0;	local_int_config.sh_local_int0_config_s.pid = cpu;	local_int_config.sh_local_int0_config_s.base = 0;	local_int_config.sh_local_int0_config_s.idx = SGI_UART_VECTOR;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_CONFIG),		local_int_config.sh_local_int0_config_regval);	// LOCAL_INT1 is for all hardware errors.	// It will send a BERR, which will result in an MCA.	local_int_config.sh_local_int0_config_s.idx = 0;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),		local_int_config.sh_local_int0_config_regval);	// Clear the LOCAL_INT_ENABLE register.	local_int_enable.sh_local_int0_enable_regval = 0;	if (is_console) {		// Enable the UART interrupt.  Only applies to the console nasid.		local_int_enable.sh_local_int0_enable_s.uart_int = 1;		HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_ENABLE),			local_int_enable.sh_local_int0_enable_regval);	}	// Enable all the error interrupts.	local_int_enable.sh_local_int0_enable_s.uart_int = 0;	local_int_enable.sh_local_int0_enable_s.pi_hw_int = 1;	local_int_enable.sh_local_int0_enable_s.md_hw_int = 1;	local_int_enable.sh_local_int0_enable_s.xn_hw_int = 1;	local_int_enable.sh_local_int0_enable_s.lb_hw_int = 1;	local_int_enable.sh_local_int0_enable_s.ii_hw_int = 1;	local_int_enable.sh_local_int0_enable_s.pi_uce_int = 1;	local_int_enable.sh_local_int0_enable_s.md_uce_int = 1;	local_int_enable.sh_local_int0_enable_s.xn_uce_int = 1;	local_int_enable.sh_local_int0_enable_s.system_shutdown_int = 1;	local_int_enable.sh_local_int0_enable_s.l1_nmi_int = 1;	local_int_enable.sh_local_int0_enable_s.stop_clock = 1;	// Send BERR, rather than an interrupt, for shub errors.	local_int_config.sh_local_int0_config_s.agt = 1;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),		local_int_config.sh_local_int0_config_regval);	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_ENABLE),		local_int_enable.sh_local_int0_enable_regval);	// Make sure BERR is enabled.	fsb_system_agent.sh_fsb_system_agent_config_regval = 		HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG) );	fsb_system_agent.sh_fsb_system_agent_config_s.berr_assert_en = 1;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG),		fsb_system_agent.sh_fsb_system_agent_config_regval);	// Set LOCAL_INT2 to field CEs	local_int_enable.sh_local_int0_enable_regval = 0;	local_int_config.sh_local_int0_config_s.agt = 0;	local_int_config.sh_local_int0_config_s.idx = SGI_SHUB_ERROR_VECTOR;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_CONFIG),		local_int_config.sh_local_int0_config_regval);	local_int_enable.sh_local_int0_enable_s.pi_ce_int = 1;	local_int_enable.sh_local_int0_enable_s.md_ce_int = 1;	local_int_enable.sh_local_int0_enable_s.xn_ce_int = 1;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_ENABLE),		local_int_enable.sh_local_int0_enable_regval);	// Make sure all the rest of the LOCAL_INT regs are disabled.	local_int_enable.sh_local_int0_enable_regval = 0;	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT3_ENABLE),		local_int_enable.sh_local_int0_enable_regval);	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT4_ENABLE),		local_int_enable.sh_local_int0_enable_regval);	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE),		local_int_enable.sh_local_int0_enable_regval);}// (Un)Reserve an irq on this cpu.static intdo_intr_reserve_level(cpuid_t cpu,			int bit,			int reserve){	int i;	irqpda_t	*irqs = irqpdaindr[cpu];	if (reserve) {		if (bit < 0) {			for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {				if (irqs->irq_flags[i] == 0) {					bit = i;					break;				}			}		}		if (bit < 0) {			return -1;		}		if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) {			return -1;		} else {			irqs->num_irq_used++;			irqs->irq_flags[bit] |= SN2_IRQ_RESERVED;			return bit;		}	} else {		if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) {			irqs->num_irq_used--;			irqs->irq_flags[bit] &= ~SN2_IRQ_RESERVED;			return bit;		} else {			return -1;		}	}}intintr_reserve_level(cpuid_t cpu,		int bit,		int resflags,		devfs_handle_t owner_dev,		char *name){	return(do_intr_reserve_level(cpu, bit, 1));}voidintr_unreserve_level(cpuid_t cpu,		int bit){	(void)do_intr_reserve_level(cpu, bit, 0);}// Mark an irq on this cpu as (dis)connected.static intdo_intr_connect_level(cpuid_t cpu,			int bit,			int connect){	irqpda_t	*irqs = irqpdaindr[cpu];	if (connect) {		if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) {			return -1;		} else {			irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED;			return bit;		}	} else {		if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) {			irqs->irq_flags[bit] &= ~SN2_IRQ_CONNECTED;			return bit;		} else {			return -1;		}	}	return(bit);}intintr_connect_level(cpuid_t cpu,		int bit,		ilvl_t is,		intr_func_t intr_prefunc){	return(do_intr_connect_level(cpu, bit, 1));}intintr_disconnect_level(cpuid_t cpu,		int bit){	return(do_intr_connect_level(cpu, bit, 0));}// Choose a cpu on this node.// We choose the one with the least number of int's assigned to it.static cpuid_tdo_intr_cpu_choose(cnodeid_t cnode) {	cpuid_t		cpu, best_cpu = CPU_NONE;	int		slice, min_count = 1000;	irqpda_t	*irqs;	for (slice = 0; slice < CPUS_PER_NODE; slice++) {		int intrs;		cpu = cnode_slice_to_cpuid(cnode, slice);		if (cpu == CPU_NONE) {			continue;		}		if (!cpu_enabled(cpu)) {			continue;		}		irqs = irqpdaindr[cpu];		intrs = irqs->num_irq_used;		if (min_count > intrs) {			min_count = intrs;			best_cpu = cpu;		}	}	return best_cpu;}static cpuid_tintr_cpu_choose_from_node(cnodeid_t cnode){	return(do_intr_cpu_choose(cnode));}// See if we can use this cpu/vect.static cpuid_tintr_bit_reserve_test(cpuid_t cpu,			int favor_subnode,			cnodeid_t cnode,			int req_bit,			int resflags,			devfs_handle_t owner_dev,			char *name,			int *resp_bit){	ASSERT( (cpu == CPU_NONE) || (cnode == CNODEID_NONE) );	if (cnode != CNODEID_NONE) {		cpu = intr_cpu_choose_from_node(cnode);	}	if (cpu != CPU_NONE) {		*resp_bit = do_intr_reserve_level(cpu, req_bit, 1);		if (*resp_bit >= 0) {			return(cpu);		}	}	return CPU_NONE;}// Find the node to assign for this interrupt.cpuid_tintr_heuristic(devfs_handle_t dev,		device_desc_t dev_desc,		int	req_bit,		int resflags,		devfs_handle_t owner_dev,		char *name,		int *resp_bit){	cpuid_t		cpuid;	cnodeid_t	candidate = -1;	devfs_handle_t	pconn_vhdl;	pcibr_soft_t	pcibr_soft;/* SN2 + pcibr addressing limitation *//* Due to this limitation, all interrupts from a given bridge must go to the name node.*//* This limitation does not exist on PIC. */	if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) &&		( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) {			if (pcibr_soft->bsi_err_intr) {				candidate = cpuid_to_cnodeid( ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid);			}	}	if (candidate >= 0) {		// The node was chosen already when we assigned the error interrupt.		cpuid = intr_bit_reserve_test(CPU_NONE,						0,						candidate,						req_bit,						0,						owner_dev,						name,						resp_bit);	} else {		// Need to choose one.  Try the controlling c-brick first.		cpuid = intr_bit_reserve_test(CPU_NONE,						0,						master_node_get(dev),						req_bit,						0,						owner_dev,						name,						resp_bit);	}	if (cpuid != CPU_NONE) {		return cpuid;	}	if (candidate >= 0) {		printk("Cannot target interrupt to target node (%d).\n",candidate);		return CPU_NONE;	} else {		printk("Cannot target interrupt to closest node (%d) 0x%p\n",			master_node_get(dev), (void *)owner_dev);	}	// We couldn't put it on the closest node.  Try to find another one.	// Do a stupid round-robin assignment of the node.	{		static cnodeid_t last_node = -1;		if (last_node >= numnodes) last_node = 0;		for (candidate = last_node + 1; candidate != last_node; candidate++) {			if (candidate == numnodes) candidate = 0;			cpuid = intr_bit_reserve_test(CPU_NONE,							0,							candidate,							req_bit,							0,							owner_dev,							name,							resp_bit);			if (cpuid != CPU_NONE) {				return cpuid;			}		}	}	printk("cannot target interrupt: 0x%p\n",(void *)owner_dev);	return CPU_NONE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -