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

📄 ml_sn_intr.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
 */static hub_intmasks_t *intr_get_ptrs(cpuid_t cpu, int bit,	      int *new_bit,		/* Bit relative to the register */	      hubreg_t **intpend_masks, /* Masks for this register */	      intr_vecblk_t **vecblk,	/* Vecblock for this interrupt */	      int *ip)			/* Which intpend register */{	hub_intmasks_t *hub_intmasks;	synergy_da_t	*sda;	int		which_synergy;	cnodeid_t	cnode;	ASSERT(bit < N_INTPEND_BITS * 2);	cnode = cpuid_to_cnodeid(cpu);	which_synergy = cpuid_to_synergy(cpu);	sda = Synergy_da_indr[(cnode * 2) + which_synergy];	hub_intmasks = &sda->s_intmasks;	// hub_intmasks = &pdaindr[cpu].pda->p_intmasks;	if (bit < N_INTPEND_BITS) {		*intpend_masks = hub_intmasks->intpend0_masks;		*vecblk = hub_intmasks->dispatch0;		*ip = 0;		*new_bit = bit;	} else {		*intpend_masks = hub_intmasks->intpend1_masks;		*vecblk = hub_intmasks->dispatch1;		*ip = 1;		*new_bit = bit - N_INTPEND_BITS;	}	return hub_intmasks;}/* * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel,  *		intr_func_t intr_func, void *intr_arg); *	This is the lowest-level interface to the interrupt code.  It shouldn't *	be called from outside the ml/SN directory. *	intr_connect_level hooks up an interrupt to a particular bit in *	the INT_PEND0/1 masks.  Returns 0 on success. *		cpu is the CPU to which the interrupt will be sent. *		bit is the level bit to connect to *		intr_swlevel tells which software level to use *		intr_func is the interrupt handler *		intr_arg is an arbitrary argument interpreted by the handler *		intr_prefunc is a prologue function, to be called *			with interrupts disabled, to disable *			the interrupt at source.  It is called *			with the same argument.  Should be NULL for *			typical interrupts, which can be masked *			by the infrastructure at the level bit. *	intr_connect_level returns 0 on success or nonzero on an error *//* ARGSUSED */intintr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, intr_func_t intr_prefunc){    intr_vecblk_t	*vecblk;    hubreg_t		*intpend_masks;    int rv = 0;    int ip;    unsigned long s;    ASSERT(bit < N_INTPEND_BITS * 2);    (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks,				 &vecblk, &ip);    INTR_LOCK(vecblk);    if ((vecblk->info[bit].ii_flags & II_INUSE) ||	(!(vecblk->info[bit].ii_flags & II_RESERVE))) {	/* Can't assign to a level that's in use or isn't reserved. */	rv = -1;    } else {	/* Stuff parameters into vector and info */	vecblk->vectors[bit].iv_prefunc = intr_prefunc;	vecblk->info[bit].ii_flags |= II_INUSE;    }    /* Now stuff the masks if everything's okay. */    if (!rv) {	int lslice;	volatile hubreg_t *mask_reg;	// nasid_t nasid = COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu));	nasid_t nasid = cpuid_to_nasid(cpu);	int	subnode = cpuid_to_subnode(cpu);	/* Make sure it's not already pending when we connect it. */	REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS);	if (bit >= GFX_INTR_A && bit <= CC_PEND_B) {		intpend_masks[0] |= (1ULL << (uint64_t)bit);	}	lslice = cpuid_to_localslice(cpu);	vecblk->cpu_count[lslice]++;#if SN1	/*	 * On SN1, there are 8 interrupt mask registers per node:	 * 	PI_0 MASK_0 A	 * 	PI_0 MASK_1 A	 * 	PI_0 MASK_0 B	 * 	PI_0 MASK_1 B	 * 	PI_1 MASK_0 A	 * 	PI_1 MASK_1 A	 * 	PI_1 MASK_0 B	 * 	PI_1 MASK_1 B	 */#endif	if (ip == 0) {		mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, 		        PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice);	} else {		mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode,			PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice);	}	HUB_S(mask_reg, intpend_masks[0]);    }    INTR_UNLOCK(vecblk);    return rv;}/* * intr_disconnect_level(cpuid_t cpu, int bit) * *	This is the lowest-level interface to the interrupt code.  It should *	not be called from outside the ml/SN directory. *	intr_disconnect_level removes a particular bit from an interrupt in * 	the INT_PEND0/1 masks.  Returns 0 on success or nonzero on failure. */intintr_disconnect_level(cpuid_t cpu, int bit){    intr_vecblk_t	*vecblk;    hubreg_t		*intpend_masks;    unsigned long s;    int rv = 0;    int ip;    (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks,				 &vecblk, &ip);    INTR_LOCK(vecblk);    if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) !=	((II_RESERVE | II_INUSE))) {	/* Can't remove a level that's not in use or isn't reserved. */	rv = -1;    } else {	/* Stuff parameters into vector and info */	vecblk->vectors[bit].iv_func = (intr_func_t)NULL;	vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL;	vecblk->vectors[bit].iv_arg = 0;	vecblk->info[bit].ii_flags &= ~II_INUSE;#ifdef BASE_ITHRTEAD	vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */#endif    }    /* Now clear the masks if everything's okay. */    if (!rv) {	int lslice;	volatile hubreg_t *mask_reg;	intpend_masks[0] &= ~(1ULL << (uint64_t)bit);	lslice = cpuid_to_localslice(cpu);	vecblk->cpu_count[lslice]--;	mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), 				   cpuid_to_subnode(cpu),				   ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A);	mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg +					(PI_INT_MASK_OFFSET * lslice));	*mask_reg = intpend_masks[0];    }    INTR_UNLOCK(vecblk);    return rv;}/* * Actually block or unblock an interrupt */voiddo_intr_block_bit(cpuid_t cpu, int bit, int block){	intr_vecblk_t *vecblk;	int ip;	unsigned long s;	hubreg_t *intpend_masks;	volatile hubreg_t mask_value;	volatile hubreg_t *mask_reg;	intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip);	INTR_LOCK(vecblk);	if (block)		/* Block */		intpend_masks[0] &= ~(1ULL << (uint64_t)bit);	else		/* Unblock */		intpend_masks[0] |= (1ULL << (uint64_t)bit);	if (ip == 0) {		mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), 		        cpuid_to_subnode(cpu), PI_INT_MASK0_A);	} else {		mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), 			cpuid_to_subnode(cpu), PI_INT_MASK1_A);	}	HUB_S(mask_reg, intpend_masks[0]);	/*	 * Wait for it to take effect.  (One read should suffice.)	 * This is only necessary when blocking an interrupt	 */	if (block)		while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0])			;	INTR_UNLOCK(vecblk);}/* * Block a particular interrupt (cpu/bit pair). *//* ARGSUSED */voidintr_block_bit(cpuid_t cpu, int bit){	do_intr_block_bit(cpu, bit, 1);}/* * Unblock a particular interrupt (cpu/bit pair). *//* ARGSUSED */voidintr_unblock_bit(cpuid_t cpu, int bit){	do_intr_block_bit(cpu, bit, 0);}/* verifies that the specified CPUID is on the specified SUBNODE (if any) */#define cpu_on_subnode(cpuid, which_subnode) \	   (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode)))/* * Choose one of the CPUs on a specified node or subnode to receive * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu. * * Among all acceptable CPUs, the CPU that has the fewest total number * of interrupts targetted towards it is chosen.  Note that we never * consider how frequent each of these interrupts might occur, so a rare * hardware error interrupt is weighted equally with a disk interrupt. */static cpuid_tdo_intr_cpu_choose(cnodeid_t cnode, int which_subnode){	cpuid_t 	cpu, best_cpu = CPU_NONE;	int		slice, min_count=1000;	min_count = 1000;	for (slice=0; slice < CPUS_PER_NODE; slice++) {		intr_vecblk_t 	*vecblk0, *vecblk1;		int total_intrs_to_slice;		subnode_pda_t *snpda;		int local_cpu_num;		cpu = cnode_slice_to_cpuid(cnode, slice);		if (cpu == CPU_NONE)			continue;		/* If this cpu isn't enabled for interrupts, skip it */		if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu))			continue;		/* If this isn't the right subnode, skip it */		if (!cpu_on_subnode(cpu, which_subnode))			continue;		/* OK, this one's a potential CPU for interrupts */		snpda = SUBNODEPDA(cnode,SUBNODE(slice));		vecblk0 = &snpda->intr_dispatch0;		vecblk1 = &snpda->intr_dispatch1;		local_cpu_num = LOCALCPU(slice);		total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] +		              vecblk1->cpu_count[local_cpu_num];		if (min_count > total_intrs_to_slice) {			min_count = total_intrs_to_slice;			best_cpu = cpu;		}	}	return best_cpu;}/* * Choose an appropriate interrupt target CPU on a specified node. * If which_subnode is SUBNODE_ANY, then subnode is not considered. * Otherwise, the chosen CPU must be on the specified subnode. */static cpuid_tintr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode){	return(do_intr_cpu_choose(cnode, which_subnode));}/* Make it easy to identify subnode vertices in the hwgraph */voidmark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode){	graph_error_t rv;	ASSERT(0 <= which_subnode);	ASSERT(which_subnode < NUM_SUBNODES);	rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode);	ASSERT_ALWAYS(rv == GRAPH_SUCCESS);	rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t));	ASSERT_ALWAYS(rv == GRAPH_SUCCESS);}/* * Given a device descriptor, extract interrupt target information and * choose an appropriate CPU.  Return CPU_NONE if we can't make sense * out of the target information. * TBD: Should this be considered platform-independent code? *//* * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags, *		owner_dev,intr_name,*resp_bit) *	Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but * 	not both. * 1. 	If cpuid is specified, this routine tests if this cpu can be a valid * 	interrupt target candidate. * 2. 	If cnodeid is specified, this routine tests if there is a cpu on  *	this node which can be a valid interrupt target candidate. * 3.	If a valid interrupt target cpu candidate is found then an attempt at  * 	reserving an interrupt bit on the corresponding cnode is made. * * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid * interrupt target cpu then routine returns CPU_NONE (failure) * Otherwise routine returns cpuid of interrupt target (success) */static cpuid_tintr_bit_reserve_test(cpuid_t 		cpuid,		      int		favor_subnode,		      cnodeid_t 	cnodeid,		      int		req_bit,		      int 		intr_resflags,		      devfs_handle_t 	owner_dev,		      char		*intr_name,		      int		*resp_bit){	ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE));	if (cnodeid != CNODEID_NONE) {		/* Try to choose a interrupt cpu candidate */		cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode);	}	if (cpuid != CPU_NONE) {

⌨️ 快捷键说明

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