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

📄 ml_sn_intr.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $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 IP27 board. */#ident  "$Revision: 1.1 $"#include <linux/types.h>#include <linux/config.h>#include <linux/slab.h>#include <asm/smp.h>#include <asm/sn/sgi.h>#include <asm/sn/io.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.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>#if DEBUG_INTR_TSTAMP_DEBUG#include <sys/debug.h>#include <sys/idbg.h>#include <sys/inst.h>void do_splx_log(int, int);void spldebug_log_event(int);#endif#ifdef CONFIG_SMPextern unsigned long cpu_online_map;#endif#define cpu_allows_intr(cpu)	(1)// If I understand what's going on with this, 32 should work.// physmem_maxradius seems to be the maximum number of router// hops to get from one end of the system to the other.  With// a maximally configured machine, with the dumbest possible// topology, we would make 32 router hops.  For what we're using// it for, the dumbest possible should suffice.#define physmem_maxradius()	32#define SUBNODE_ANY (-1)extern int	nmied;extern int	hub_intr_wakeup_cnt;extern synergy_da_t	*Synergy_da_indr[];extern cpuid_t         master_procid;extern cnodeid_t master_node_get(devfs_handle_t vhdl);extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs);#define INTR_LOCK(vecblk) \     (s = mutex_spinlock(&(vecblk)->vector_lock))#define INTR_UNLOCK(vecblk) \      mutex_spinunlock(&(vecblk)->vector_lock, s)/* * REACT/Pro *//*  * Find first bit set  * Used outside this file also  */int ms1bit(unsigned long x){    int			b;    if (x >> 32)	b  = 32, x >>= 32;    else		b  =  0;    if (x >> 16)	b += 16, x >>= 16;    if (x >>  8)	b +=  8, x >>=  8;    if (x >>  4)	b +=  4, x >>=  4;    if (x >>  2)	b +=  2, x >>=  2;    return b + (int) (x >> 1);}/* ARGSUSED */voidintr_stray(void *lvl){    printk(KERN_WARNING  "Stray Interrupt - level %ld to cpu %d", (long)lvl, smp_processor_id());}#if defined(DEBUG)/* Infrastructure  to gather the device - target cpu mapping info */#define MAX_DEVICES	1000	/* Reasonable large number . Need not be 				 * the exact maximum # devices possible.				 */#define MAX_NAME	100	typedef struct {	dev_t		dev;	/* device */	cpuid_t		cpuid;	/* target cpu */	cnodeid_t	cnodeid;/* node on which the target cpu is present */	int		bit;	/* intr bit reserved */	char		intr_name[MAX_NAME]; /* name of the interrupt */} intr_dev_targ_map_t;intr_dev_targ_map_t 	intr_dev_targ_map[MAX_DEVICES];uint64_t		intr_dev_targ_map_size;spinlock_t		intr_dev_targ_map_lock;/* Print out the device - target cpu mapping. * This routine is used only in the idbg command * "intrmap"  */voidintr_dev_targ_map_print(cnodeid_t cnodeid){	int  i,j,size = 0;	int  print_flag = 0,verbose = 0;		char node_name[10];		if (cnodeid != CNODEID_NONE) {		nodepda_t 	*npda;		npda = NODEPDA(cnodeid);		for (j=0; j<NUM_SUBNODES; j++) {			qprintf("\n SUBNODE %d\n INT_PEND0: ", j);			for(i = 0 ; i < N_INTPEND_BITS ; i++)				qprintf("%d",SNPDA(npda,j)->intr_dispatch0.info[i].ii_flags);			qprintf("\n INT_PEND1: ");			for(i = 0 ; i < N_INTPEND_BITS ; i++)				qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags);		}		verbose = 1;	}	qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n",		(verbose ? "All" : "Non-hardwired"),		(cnodeid == CNODEID_NONE) ? "s: All" : node_name); 			qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n");	for (i = 0 ; i < intr_dev_targ_map_size ; i++) {		print_flag = 0;		if (verbose) {			if (cnodeid != CNODEID_NONE) {				if (cnodeid == intr_dev_targ_map[i].cnodeid)					print_flag = 1;			} else {				print_flag = 1;			}		} else {			if (intr_dev_targ_map[i].dev != 0) {				if (cnodeid != CNODEID_NONE) {					if (cnodeid == 					    intr_dev_targ_map[i].cnodeid)						print_flag = 1;				} else {					print_flag = 1;				}			}		}		if (print_flag) {			size++;			qprintf("%d\t%d\t%d\t%d\t%s\n",				intr_dev_targ_map[i].dev,				intr_dev_targ_map[i].cpuid,				intr_dev_targ_map[i].cnodeid,				intr_dev_targ_map[i].bit,				intr_dev_targ_map[i].intr_name);		}	}	qprintf("\nTotal : %d\n",size);}#endif /* DEBUG *//* * The spinlocks have already been initialized.  Now initialize the interrupt * vectors.  One processor on each hub does the work. */voidintr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn){    int			i, ip=0;    intr_vecblk_t	*vecblk;    subnode_pda_t	*snpda;    snpda = SNPDA(npda,sn);    do {	if (ip == 0) {	    vecblk = &snpda->intr_dispatch0;	} else {	    vecblk = &snpda->intr_dispatch1;	}	/* Initialize this vector. */	for (i = 0; i < N_INTPEND_BITS; i++) {		vecblk->vectors[i].iv_func = intr_stray;		vecblk->vectors[i].iv_prefunc = NULL;		vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i);		vecblk->info[i].ii_owner_dev = 0;		strcpy(vecblk->info[i].ii_name, "Unused");		vecblk->info[i].ii_flags = 0;	/* No flags */		vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */	    }	mutex_spinlock_init(&vecblk->vector_lock);	vecblk->vector_count = 0;    	for (i = 0; i < CPUS_PER_SUBNODE; i++)		vecblk->cpu_count[i] = 0;	vecblk->vector_state = VECTOR_UNINITED;    } while (++ip < 2);}/* * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve,  *					devfs_handle_t owner_dev, char *name) *	Internal work routine to reserve or unreserve an interrupt level. *		cpu is the CPU to which the interrupt will be sent. *		bit is the level bit to reserve.  -1 means any level *		resflags should include II_ERRORINT if this is an *			error interrupt, II_THREADED if the interrupt handler *			will be threaded, or 0 otherwise. *		reserve should be set to II_RESERVE or II_UNRESERVE *			to get or clear a reservation. *		owner_dev is the device that "owns" this interrupt, if supplied *		name is a human-readable name for this interrupt, if supplied *	intr_reserve_level returns the bit reserved or -1 to indicate an error */static intdo_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, 					devfs_handle_t owner_dev, char *name){    intr_vecblk_t	*vecblk;    hub_intmasks_t 	*hub_intmasks;    unsigned long s;    int rv = 0;    int ip;    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 (pdaindr[cpu].pda == NULL) return -1;    if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) {	vecblk = hub_intmasks->dispatch0;	ip = 0;    } else {	ASSERT((bit >= N_INTPEND_BITS) || (bit == -1));	bit -= N_INTPEND_BITS;	/* Get position relative to INT_PEND1 reg. */	vecblk = hub_intmasks->dispatch1;	ip = 1;    }    INTR_LOCK(vecblk);    if (bit <= -1) {	bit = 0;	ASSERT(reserve == II_RESERVE);	/* Choose any available level */	for (; bit < N_INTPEND_BITS; bit++) {	    if (!(vecblk->info[bit].ii_flags & II_RESERVE)) {		rv = bit;		break;	    }	}	/* Return -1 if all interrupt levels int this register are taken. */	if (bit == N_INTPEND_BITS)	    rv = -1;    } else {	/* Reserve a particular level if it's available. */	if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) {	    /* Can't (un)reserve a level that's already (un)reserved. */	    rv = -1;	} else {	    rv = bit;	}    }    /* Reserve the level and bump the count. */    if (rv != -1) {	if (reserve) {	    int maxlen = sizeof(vecblk->info[bit].ii_name) - 1;	    int namelen;	    vecblk->info[bit].ii_flags |= (II_RESERVE | resflags);	    vecblk->info[bit].ii_owner_dev = owner_dev;	    /* Copy in the name. */	    namelen = name ? strlen(name) : 0;	    strncpy(vecblk->info[bit].ii_name, name, min(namelen, maxlen)); 	    vecblk->info[bit].ii_name[maxlen] = '\0';	    vecblk->vector_count++;	} else {	    vecblk->info[bit].ii_flags = 0;	/* Clear all the flags */	    vecblk->info[bit].ii_owner_dev = 0;	    /* Clear the name. */	    vecblk->info[bit].ii_name[0] = '\0';	    vecblk->vector_count--;	}    }    INTR_UNLOCK(vecblk);#if defined(DEBUG)    if (rv >= 0) {	    int namelen = name ? strlen(name) : 0;	    /* Gather this device - target cpu mapping information	     * in a table which can be used later by the idbg "intrmap"	     * command	     */	    s = mutex_spinlock(&intr_dev_targ_map_lock);	    if (intr_dev_targ_map_size < MAX_DEVICES) {		    intr_dev_targ_map_t	*p;		    p 		= &intr_dev_targ_map[intr_dev_targ_map_size];		    p->dev  	= owner_dev;		    p->cpuid 	= cpu; 		    p->cnodeid 	= cpuid_to_cnodeid(cpu); 		    p->bit 	= ip * N_INTPEND_BITS + rv;		    strncpy(p->intr_name,			    name,			    min(MAX_NAME,namelen));		    intr_dev_targ_map_size++;	    }	    mutex_spinunlock(&intr_dev_targ_map_lock,s);    }#endif /* DEBUG */    return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ;}/* * WARNING:  This routine should only be called from within ml/SN. *	Reserve an interrupt level. */intintr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name){	return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name));}/* * WARNING:  This routine should only be called from within ml/SN. *	Unreserve an interrupt level. */voidintr_unreserve_level(cpuid_t cpu, int bit){	(void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL);}/* * Get values that vary depending on which CPU and bit we're operating on

⌨️ 快捷键说明

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