📄 pcic.c
字号:
if ((flags & IORESOURCE_IO) != 0) { if (address < 0x10000) { /* * A device responds to I/O cycles on PCI. * We generate these cycles with memory * access into the fixed map (phys 0x30000000). * * Since a device driver does not want to * do ioremap() before accessing PC-style I/O, * we supply virtual, ready to access address. * * Ebus devices do not come here even if * CheerIO makes a similar conversion. * See ebus.c for details. * * Note that check_region()/request_region() * work for these devices. * * XXX Neat trick, but it's a *bad* idea * to shit into regions like that. * What if we want to allocate one more * PCI base address... */ dev->resource[j].start = pcic->pcic_io + address; dev->resource[j].end = 1; /* XXX */ dev->resource[j].flags = (flags & ~IORESOURCE_IO) | IORESOURCE_MEM; } else { /* * OOPS... PCI Spec allows this. Sun does * 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 short 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_word(dev, PCI_COMMAND, &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_word(dev, PCI_COMMAND, 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_word(dev, PCI_COMMAND, 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 void pcic_timer_handler (int irq, void *h, struct pt_regs *regs){ pcic_clear_clock_irq(); do_timer(regs);}#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(); } __sti();}static __inline__ unsigned long do_gettimeoffset(void){ struct tasklet_struct *t; unsigned long offset = 0; /* * 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); t = &bh_task_vec[TIMER_BH]; if (test_bit(TASKLET_STATE_SCHED, &t->state)) offset = 1000000; return offset + count;}extern volatile unsigned long wall_jiffies;static void pci_do_gettimeofday(struct timeval *tv){ unsigned long flags; save_and_cli(flags); *tv = xtime; tv->tv_usec += do_gettimeoffset(); /* * xtime is atomically updated in timer_bh. The difference * between jiffies and wall_jiffies is nonzero if the timer * bottom half hasnt executed yet. */ if ((jiffies - wall_jiffies) != 0) tv->tv_usec += USECS_PER_JIFFY; restore_flags(flags); if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; } }static void pci_do_settimeofday(struct timeval *tv){ cli(); tv->tv_usec -= do_gettimeoffset(); if(tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; sti();}#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_update_resource(struct pci_dev *pdev, struct resource *res1, struct resource *res2, int index){}void pcibios_align_resource(void *data, struct resource *res, unsigned long size){}int pcibios_enable_device(struct pci_dev *pdev){ 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); save_and_cli(flags); writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); restore_flags(flags);}static void pcic_enable_irq(unsigned int irq_nr){ unsigned long mask, flags; mask = get_irqmask(irq_nr); save_and_cli(flags); writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); restore_flags(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 is local cli()'d 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; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -