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

📄 xics.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
字号:
/*  * arch/ppc/kernel/xics.c * * Copyright 2000 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. */#include <linux/config.h>#include <linux/types.h>#include <linux/threads.h>#include <linux/kernel.h>#include <linux/sched.h>#include <asm/prom.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/smp.h>#include <asm/naca.h>#include <asm/rtas.h>#include "i8259.h"#include "xics.h"#include <asm/ppcdebug.h>void xics_enable_irq(u_int irq);void xics_disable_irq(u_int irq);void xics_mask_and_ack_irq(u_int irq);void xics_end_irq(u_int irq);void xics_set_affinity(unsigned int irq_nr, unsigned long cpumask);struct hw_interrupt_type xics_pic = {	" XICS     ",	NULL,	NULL,	xics_enable_irq,	xics_disable_irq,	xics_mask_and_ack_irq,	xics_end_irq,	xics_set_affinity};struct hw_interrupt_type xics_8259_pic = {	" XICS/8259",	NULL,	NULL,	NULL,	NULL,	xics_mask_and_ack_irq,	NULL};#define XICS_IPI		2#define XICS_IRQ_OFFSET		0x10#define XICS_IRQ_SPURIOUS	0/* Want a priority other than 0.  Various HW issues require this. */#define	DEFAULT_PRIORITY	5struct xics_ipl {	union {		u32	word;		u8	bytes[4];	} xirr_poll;	union {		u32 word;		u8	bytes[4];	} xirr;	u32	dummy;	union {		u32	word;		u8	bytes[4];	} qirr;};struct xics_info {	volatile struct xics_ipl *	per_cpu[NR_CPUS];};struct xics_info	xics_info;unsigned long long intr_base = 0;int xics_irq_8259_cascade = 0;int xics_irq_8259_cascade_real = 0;unsigned int default_server = 0xFF;unsigned int default_distrib_server = 0;/* RTAS service tokens */int ibm_get_xive;int ibm_set_xive;int ibm_int_off;struct xics_interrupt_node {	unsigned long long addr;	unsigned long long size;} inodes[NR_CPUS*2];	 typedef struct {	int (*xirr_info_get)(int cpu);	void (*xirr_info_set)(int cpu, int val);	void (*cppr_info)(int cpu, u8 val);	void (*qirr_info)(int cpu, u8 val);} xics_ops;static int pSeries_xirr_info_get(int n_cpu){	return (xics_info.per_cpu[n_cpu]->xirr.word);}static void pSeries_xirr_info_set(int n_cpu, int value){	xics_info.per_cpu[n_cpu]->xirr.word = value;}static void pSeries_cppr_info(int n_cpu, u8 value){	xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value;}static void pSeries_qirr_info(int n_cpu , u8 value){	xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value;}static xics_ops pSeries_ops = {	pSeries_xirr_info_get,	pSeries_xirr_info_set,	pSeries_cppr_info,	pSeries_qirr_info};static xics_ops *ops = &pSeries_ops;extern xics_ops pSeriesLP_ops;voidxics_enable_irq(	u_int	virq	){	u_int		irq;	unsigned long	status;	long	        call_status;	virq -= XICS_IRQ_OFFSET;	irq = virt_irq_to_real(virq);	if (irq == XICS_IPI)		return;#ifdef CONFIG_IRQ_ALL_CPUS	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,				irq, smp_threads_ready ? default_distrib_server : default_server, DEFAULT_PRIORITY);#else	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,				irq, default_server, DEFAULT_PRIORITY);#endif	if( call_status != 0 ) {		printk("xics_enable_irq: irq=%x: rtas_call failed; retn=%lx, status=%lx\n",		       irq, call_status, status);		return;	}}voidxics_disable_irq(	u_int	virq	){	u_int		irq;	unsigned long 	status;	long 	        call_status;	virq -= XICS_IRQ_OFFSET;	irq = virt_irq_to_real(virq);	call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, 				irq);	if( call_status != 0 ) {		printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n",		       irq, call_status);		return;	}}voidxics_end_irq(	u_int	irq	){	int cpu = smp_processor_id();	ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */	iosync();	ops->xirr_info_set(cpu, ((0xff<<24) | (virt_irq_to_real(irq-XICS_IRQ_OFFSET))));	iosync();}voidxics_mask_and_ack_irq(u_int	irq){	int cpu = smp_processor_id();	if( irq < XICS_IRQ_OFFSET ) {		i8259_pic.ack(irq);		iosync();		ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade_real));		iosync();	}	else {		ops->cppr_info(cpu, 0xff);		iosync();	}}intxics_get_irq(struct pt_regs *regs){	u_int	cpu = smp_processor_id();	u_int	vec;	int irq;	vec = ops->xirr_info_get(cpu);	/*  (vec >> 24) == old priority */	vec &= 0x00ffffff;	/* for sanity, this had better be < NR_IRQS - 16 */	if( vec == xics_irq_8259_cascade_real ) {		irq = i8259_irq(cpu);		if(irq == -1) {			/* Spurious cascaded interrupt.  Still must ack xics */                        xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade);			irq = -1;		}	} else if( vec == XICS_IRQ_SPURIOUS ) {		irq = -1;	} else {		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;	}	return irq;}#ifdef CONFIG_SMPvoid xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs){	extern volatile unsigned long xics_ipi_message[];	int cpu = smp_processor_id();	ops->qirr_info(cpu, 0xff);	while (xics_ipi_message[cpu]) {		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu])) {			mb();			smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);		}		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu])) {			mb();			smp_message_recv(PPC_MSG_RESCHEDULE, regs);		}#ifdef CONFIG_XMON		if (test_and_clear_bit(PPC_MSG_XMON_BREAK, &xics_ipi_message[cpu])) {			mb();			smp_message_recv(PPC_MSG_XMON_BREAK, regs);		}#endif	}}void xics_cause_IPI(int cpu){	ops->qirr_info(cpu,0) ;}void xics_setup_cpu(void){	int cpu = smp_processor_id();	ops->cppr_info(cpu, 0xff);	iosync();}#endif /* CONFIG_SMP */voidxics_init_IRQ( void ){	int i;	unsigned long intr_size = 0;	struct device_node *np;	uint *ireg, ilen, indx=0;	ppc64_boot_msg(0x20, "XICS Init");	ibm_get_xive = rtas_token("ibm,get-xive");	ibm_set_xive = rtas_token("ibm,set-xive");	ibm_int_off = rtas_token("ibm,int-off");	np = find_type_devices("PowerPC-External-Interrupt-Presentation");	if (!np) {		printk(KERN_WARNING "Can't find Interrupt Presentation\n");		udbg_printf("Can't find Interrupt Presentation\n");		while (1);	}nextnode:	ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0);	if (ireg) {		/*		 * set node starting index for this node		 */		indx = *ireg;	}	ireg = (uint *)get_property(np, "reg", &ilen);	if (!ireg) {		printk(KERN_WARNING "Can't find Interrupt Reg Property\n");		udbg_printf("Can't find Interrupt Reg Property\n");		while (1);	}		while (ilen) {		inodes[indx].addr = (unsigned long long)*ireg++ << 32;		ilen -= sizeof(uint);		inodes[indx].addr |= *ireg++;		ilen -= sizeof(uint);		inodes[indx].size = (unsigned long long)*ireg++ << 32;		ilen -= sizeof(uint);		inodes[indx].size |= *ireg++;		ilen -= sizeof(uint);		indx++;		if (indx >= NR_CPUS) break;	}	np = np->next;	if ((indx < NR_CPUS) && np) goto nextnode;	/* Find the server numbers for the boot cpu. */	for (np = find_type_devices("cpu"); np; np = np->next) {		ireg = (uint *)get_property(np, "reg", &ilen);		if (ireg && ireg[0] == hard_smp_processor_id()) {			ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);			i = ilen / sizeof(int);			if (ireg && i > 0) {				default_server = ireg[0];				default_distrib_server = ireg[i-1]; /* take last element */			}			break;		}	}	intr_base = inodes[0].addr;	intr_size = (ulong)inodes[0].size;	np = find_type_devices("interrupt-controller");	if (!np) {		printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");		xics_irq_8259_cascade_real = -1;		xics_irq_8259_cascade = -1;	} else {		ireg = (uint *) get_property(np, "interrupts", 0);		if (!ireg) {			printk(KERN_WARNING "Can't find ISA Interrupts Property\n");			udbg_printf("Can't find ISA Interrupts Property\n");			while (1);		}		xics_irq_8259_cascade_real = *ireg;		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);	}	if (naca->platform == PLATFORM_PSERIES) {#ifdef CONFIG_SMP		for (i = 0; i < naca->processorCount; ++i) {			xics_info.per_cpu[i] =			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);		}#else		xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE);#endif /* CONFIG_SMP */#ifdef CONFIG_PPC_PSERIES	/* actually iSeries does not use any of xics...but it has link dependencies	 * for now, except this new one...	 */	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {		ops = &pSeriesLP_ops;#endif	}	xics_8259_pic.enable = i8259_pic.enable;	xics_8259_pic.disable = i8259_pic.disable;	for (i = 0; i < 16; ++i)		irq_desc[i].handler = &xics_8259_pic;	for (; i < NR_IRQS; ++i)		irq_desc[i].handler = &xics_pic;	ops->cppr_info(0, 0xff);	iosync();	if (xics_irq_8259_cascade != -1) {		if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,				0, "8259 cascade", 0))			printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");		i8259_init();	}#ifdef CONFIG_SMP	real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] = XICS_IPI;	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);	irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;#endif	ppc64_boot_msg(0x21, "XICS Done");}void xics_isa_init(void){	return;	if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,			0, "8259 cascade", 0))		printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");	i8259_init();}/* * Find first logical cpu and return its physical cpu number */static inline u32 physmask(u32 cpumask){	int i;	for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1) {		if (cpumask & 1)			return get_hard_smp_processor_id(i);	}	printk(KERN_ERR "xics_set_affinity: invalid irq mask\n");	return default_distrib_server;}void xics_set_affinity(unsigned int virq, unsigned long cpumask){        irq_desc_t *desc = irq_desc + virq;	unsigned int irq;	unsigned long flags;	long status;	unsigned long xics_status[2];	u32 newmask;	virq -= XICS_IRQ_OFFSET;	irq = virt_irq_to_real(virq);	if (irq == XICS_IPI)		return;        spin_lock_irqsave(&desc->lock, flags);	status = rtas_call(ibm_get_xive, 1, 3, (void *)&xics_status, irq);	if (status) {		printk("xics_set_affinity: irq=%d ibm,get-xive returns %ld\n",			irq, status);		goto out;	}	/* For the moment only implement delivery to all cpus or one cpu */	if (cpumask == 0xffffffff)		newmask = default_distrib_server;	else		newmask = physmask(cpumask);	status = rtas_call(ibm_set_xive, 3, 1, NULL,				irq, newmask, xics_status[1]);	if (status) {		printk("xics_set_affinity irq=%d ibm,set-xive returns %ld\n",			irq, status);		goto out;	}out:        spin_unlock_irqrestore(&desc->lock, flags);}

⌨️ 快捷键说明

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