pcic.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,040 行 · 第 1/2 页

C
1,040
字号
				 * not have any devices getting above 64K				 * so it must be user with a weird I/O				 * board in a PCI slot. We must remap it				 * under 64K but it is not done yet. XXX				 */				printk("PCIC: Skipping I/O space at 0x%lx,"				    "this will Oops if a driver attaches;"				    "device '%s' at %02x:%02x)\n", address,				    namebuf, dev->bus->number, dev->devfn);			}		}	}}static voidpcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node){	struct pcic_ca2irq *p;	int i, ivec;	char namebuf[64];	if (node == 0 || node == -1) {		strcpy(namebuf, "???");	} else {		prom_getstring(node, "name", namebuf, sizeof(namebuf));	}	if ((p = pcic->pcic_imap) == 0) {		dev->irq = 0;		return;	}	for (i = 0; i < pcic->pcic_imdim; i++) {		if (p->busno == dev->bus->number && p->devfn == dev->devfn)			break;		p++;	}	if (i >= pcic->pcic_imdim) {		printk("PCIC: device %s devfn %02x:%02x not found in %d\n",		    namebuf, dev->bus->number, dev->devfn, pcic->pcic_imdim);		dev->irq = 0;		return;	}	i = p->pin;	if (i >= 0 && i < 4) {		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);		dev->irq = ivec >> (i << 2) & 0xF;	} else if (i >= 4 && i < 8) {		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);		dev->irq = ivec >> ((i-4) << 2) & 0xF;	} else {					/* Corrupted map */		printk("PCIC: BAD PIN %d\n", i); for (;;) {}	}/* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */	/*	 * dev->irq=0 means PROM did not bother to program the upper	 * half of PCIC. This happens on JS-E with PROM 3.11, for instance.	 */	if (dev->irq == 0 || p->force) {		if (p->irq == 0 || p->irq >= 15) {	/* Corrupted map */			printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {}		}		printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n",		    p->irq, p->pin, dev->bus->number, dev->devfn);		dev->irq = p->irq;		i = p->pin;		if (i >= 4) {			ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);			ivec &= ~(0xF << ((i - 4) << 2));			ivec |= p->irq << ((i - 4) << 2);			writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_HI);		} else {			ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);			ivec &= ~(0xF << (i << 2));			ivec |= p->irq << (i << 2);			writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO);		} 	}	return;}/* * Normally called from {do_}pci_scan_bus... */void __init pcibios_fixup_bus(struct pci_bus *bus){	struct list_head *walk;	int i, has_io, has_mem;	unsigned int cmd;	struct linux_pcic *pcic;	/* struct linux_pbm_info* pbm = &pcic->pbm; */	int node;	struct pcidev_cookie *pcp;	if (!pcic0_up) {		printk("pcibios_fixup_bus: no PCIC\n");		return;	}	pcic = &pcic0;	/*	 * Next crud is an equivalent of pbm = pcic_bus_to_pbm(bus);	 */	if (bus->number != 0) {		printk("pcibios_fixup_bus: nonzero bus 0x%x\n", bus->number);		return;	}	walk = &bus->devices;	for (walk = walk->next; walk != &bus->devices; walk = walk->next) {		struct pci_dev *dev = pci_dev_b(walk);		/*		 * Comment from i386 branch:		 *     There are buggy BIOSes that forget to enable I/O and memory		 *     access to PCI devices. We try to fix this, but we need to		 *     be sure that the BIOS didn't forget to assign an address		 *     to the device. [mj]		 * OBP is a case of such BIOS :-)		 */		has_io = has_mem = 0;		for(i=0; i<6; i++) {			unsigned long f = dev->resource[i].flags;			if (f & IORESOURCE_IO) {				has_io = 1;			} else if (f & IORESOURCE_MEM)				has_mem = 1;		}		pcic_read_config(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);		if (has_io && !(cmd & PCI_COMMAND_IO)) {			printk("PCIC: Enabling I/O for device %02x:%02x\n",				dev->bus->number, dev->devfn);			cmd |= PCI_COMMAND_IO;			pcic_write_config(dev->bus, dev->devfn,			    PCI_COMMAND, 2, cmd);		}		if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {			printk("PCIC: Enabling memory for device %02x:%02x\n",				dev->bus->number, dev->devfn);			cmd |= PCI_COMMAND_MEMORY;			pcic_write_config(dev->bus, dev->devfn,			    PCI_COMMAND, 2, cmd);		}		node = pdev_to_pnode(&pcic->pbm, dev);		if(node == 0)			node = -1;		/* cookies */		pcp = pci_devcookie_alloc();		pcp->pbm = &pcic->pbm;		pcp->prom_node = node;		dev->sysdata = pcp;		/* fixing I/O to look like memory */		if ((dev->class>>16) != PCI_BASE_CLASS_BRIDGE)			pcic_map_pci_device(pcic, dev, node);		pcic_fill_irq(pcic, dev, node);	}}/* * pcic_pin_to_irq() is exported to ebus.c. */unsigned intpcic_pin_to_irq(unsigned int pin, char *name){	struct linux_pcic *pcic = &pcic0;	unsigned int irq;	unsigned int ivec;	if (pin < 4) {		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);		irq = ivec >> (pin << 2) & 0xF;	} else if (pin < 8) {		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);		irq = ivec >> ((pin-4) << 2) & 0xF;	} else {					/* Corrupted map */		printk("PCIC: BAD PIN %d FOR %s\n", pin, name);		for (;;) {}	/* XXX Cannot panic properly in case of PROLL */	}/* P3 */ /* printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq); */	return irq;}/* Makes compiler happy */static volatile int pcic_timer_dummy;static void pcic_clear_clock_irq(void){	pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);}static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs){	write_seqlock(&xtime_lock);	/* Dummy, to show that we remember */	pcic_clear_clock_irq();	do_timer(regs);	write_sequnlock(&xtime_lock);	return IRQ_HANDLED;}#define USECS_PER_JIFFY  10000  /* We have 100HZ "standard" timer for sparc */#define TICK_TIMER_LIMIT ((100*1000000/4)/100)void __init pci_time_init(void){	struct linux_pcic *pcic = &pcic0;	unsigned long v;	int timer_irq, irq;	/* A hack until do_gettimeofday prototype is moved to arch specific headers	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */	((unsigned int *)do_gettimeofday)[0] = 	    0x10800000 | ((((unsigned long)pci_do_gettimeofday -	     (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);	((unsigned int *)do_gettimeofday)[1] = 0x01000000;	BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);	btfixup();	writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);	/* PROM should set appropriate irq */	v = readb(pcic->pcic_regs+PCI_COUNTER_IRQ);	timer_irq = PCI_COUNTER_IRQ_SYS(v);	writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),		pcic->pcic_regs+PCI_COUNTER_IRQ);	irq = request_irq(timer_irq, pcic_timer_handler,			  (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);	if (irq) {		prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);		prom_halt();	}	local_irq_enable();}static __inline__ unsigned long do_gettimeoffset(void){	/*	 * We devide all to 100	 * to have microsecond resolution and to avoid overflow	 */	unsigned long count =	    readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;	count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);	return count;}extern unsigned long wall_jiffies;static void pci_do_gettimeofday(struct timeval *tv){	unsigned long flags;	unsigned long seq;	unsigned long usec, sec;	unsigned long max_ntp_tick = tick_usec - tickadj;	do {		unsigned long lost;		seq = read_seqbegin_irqsave(&xtime_lock, flags);		usec = do_gettimeoffset();		lost = jiffies - wall_jiffies;		/*		 * If time_adjust is negative then NTP is slowing the clock		 * so make sure not to go into next possible interval.		 * Better to lose some accuracy than have time go backwards..		 */		if (unlikely(time_adjust < 0)) {			usec = min(usec, max_ntp_tick);			if (lost)				usec += lost * max_ntp_tick;		}		else if (unlikely(lost))			usec += lost * tick_usec;		sec = xtime.tv_sec;		usec += (xtime.tv_nsec / 1000);	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));	while (usec >= 1000000) {		usec -= 1000000;		sec++;	}	tv->tv_sec = sec;	tv->tv_usec = usec;}static int pci_do_settimeofday(struct timespec *tv){	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)		return -EINVAL;	/*	 * This is revolting. We need to set "xtime" correctly. However, the	 * value in this location is the value at the most recent update of	 * wall time.  Discover what correction gettimeofday() would have	 * made, and then undo it!	 */	tv->tv_nsec -= 1000 * (do_gettimeoffset() + 				(jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));	while (tv->tv_nsec < 0) {		tv->tv_nsec += NSEC_PER_SEC;		tv->tv_sec--;	}	wall_to_monotonic.tv_sec += xtime.tv_sec - tv->tv_sec;	wall_to_monotonic.tv_nsec += xtime.tv_nsec - tv->tv_nsec;	if (wall_to_monotonic.tv_nsec > NSEC_PER_SEC) {		wall_to_monotonic.tv_nsec -= NSEC_PER_SEC;		wall_to_monotonic.tv_sec++;	}	if (wall_to_monotonic.tv_nsec < 0) {		wall_to_monotonic.tv_nsec += NSEC_PER_SEC;		wall_to_monotonic.tv_sec--;	}	xtime.tv_sec = tv->tv_sec;	xtime.tv_nsec = tv->tv_nsec;	time_adjust = 0;		/* stop active adjtime() */	time_status |= STA_UNSYNC;	time_maxerror = NTP_PHASE_LIMIT;	time_esterror = NTP_PHASE_LIMIT;	return 0;}#if 0static void watchdog_reset() {	writeb(0, pcic->pcic_regs+PCI_SYS_STATUS);}#endif/* * Other archs parse arguments here. */char * __init pcibios_setup(char *str){	return str;}void pcibios_align_resource(void *data, struct resource *res,			    unsigned long size, unsigned long align){}int pcibios_enable_device(struct pci_dev *pdev, int mask){	return 0;}/* * NMI */void pcic_nmi(unsigned int pend, struct pt_regs *regs){	pend = flip_dword(pend);	if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) {		/*		 * XXX On CP-1200 PCI #SERR may happen, we do not know		 * what to do about it yet.		 */		printk("Aiee, NMI pend 0x%x pc 0x%x spec %d, hanging\n",		    pend, (int)regs->pc, pcic_speculative);		for (;;) { }	}	pcic_speculative = 0;	pcic_trapped = 1;	regs->pc = regs->npc;	regs->npc += 4;}static inline unsigned long get_irqmask(int irq_nr){	return 1 << irq_nr;}static inline char *pcic_irq_itoa(unsigned int irq){	static char buff[16];	sprintf(buff, "%d", irq);	return buff;}static void pcic_disable_irq(unsigned int irq_nr){	unsigned long mask, flags;	mask = get_irqmask(irq_nr);	local_irq_save(flags);	writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);	local_irq_restore(flags);}static void pcic_enable_irq(unsigned int irq_nr){	unsigned long mask, flags;	mask = get_irqmask(irq_nr);	local_irq_save(flags);	writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);	local_irq_restore(flags);}static void pcic_clear_profile_irq(int cpu){	printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);}static void pcic_load_profile_irq(int cpu, unsigned int limit){	printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);}/* We assume the caller has disabled local interrupts when these are called, * or else very bizarre behavior will result. */static void pcic_disable_pil_irq(unsigned int pil){	writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);}static void pcic_enable_pil_irq(unsigned int pil){	writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);}void __init sun4m_pci_init_IRQ(void){	BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);	BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM);}int pcibios_assign_resource(struct pci_dev *pdev, int resource){	return -ENXIO;}/* * This probably belongs here rather than ioport.c because * we do not want this crud linked into SBus kernels. * Also, think for a moment about likes of floppy.c that * include architecture specific parts. They may want to redefine ins/outs. * * We do not use horroble macroses here because we want to * advance pointer by sizeof(size). */void outsb(unsigned long addr, const void *src, unsigned long count) {	while (count) {		count -= 1;		writeb(*(const char *)src, addr);		src += 1;		addr += 1;	}}void outsw(unsigned long addr, const void *src, unsigned long count) {	while (count) {		count -= 2;		writew(*(const short *)src, addr);		src += 2;		addr += 2;	}}void outsl(unsigned long addr, const void *src, unsigned long count) {	while (count) {		count -= 4;		writel(*(const long *)src, addr);		src += 4;		addr += 4;	}}void insb(unsigned long addr, void *dst, unsigned long count) {	while (count) {		count -= 1;		*(unsigned char *)dst = readb(addr);		dst += 1;		addr += 1;	}}void insw(unsigned long addr, void *dst, unsigned long count) {	while (count) {		count -= 2;		*(unsigned short *)dst = readw(addr);		dst += 2;		addr += 2;	}}void insl(unsigned long addr, void *dst, unsigned long count) {	while (count) {		count -= 4;		/*		 * XXX I am sure we are in for an unaligned trap here.		 */		*(unsigned long *)dst = readl(addr);		dst += 4;		addr += 4;	}}subsys_initcall(pcic_init);

⌨️ 快捷键说明

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