dino.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,078 行 · 第 1/3 页
C
1,078 行
gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR); gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIWOR); gsc_writel(0x00000040, dino_dev->hba.base_addr+DINO_MLTIM); gsc_writel(0x00000080, dino_dev->hba.base_addr+DINO_IO_CONTROL); gsc_writel(0x0000008c, dino_dev->hba.base_addr+DINO_TLTIM); /* Disable PAMR before writing PAPR */ gsc_writel(0x0000007e, dino_dev->hba.base_addr+DINO_PAMR); gsc_writel(0x0000007f, dino_dev->hba.base_addr+DINO_PAPR); gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_PAMR); /* ** Dino ERS encourages enabling FBB (0x6f). ** We can't until we know *all* devices below us can support it. ** (Something in device configuration header tells us). */ gsc_writel(0x0000004f, dino_dev->hba.base_addr+DINO_PCICMD); /* Somewhere, the PCI spec says give devices 1 second ** to recover from the #RESET being de-asserted. ** Experience shows most devices only need 10ms. ** This short-cut speeds up booting significantly. */ mdelay(pci_post_reset_delay);}static int __initdino_bridge_init(struct dino_device *dino_dev, const char *name){ unsigned long io_addr; int result, i, count=0; struct resource *res, *prevres = NULL; /* * Decoding IO_ADDR_EN only works for Built-in Dino * since PDC has already initialized this. */ io_addr = gsc_readl(dino_dev->hba.base_addr + DINO_IO_ADDR_EN); if (io_addr == 0) { printk(KERN_WARNING "%s: No PCI devices enabled.\n", name); return -ENODEV; } res = &dino_dev->hba.lmmio_space; for (i = 0; i < 32; i++) { unsigned long start, end; if((io_addr & (1 << i)) == 0) continue; start = (unsigned long)(signed int)(0xf0000000 | (i << 23)); end = start + 8 * 1024 * 1024 - 1; DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count, start, end); if(prevres && prevres->end + 1 == start) { prevres->end = end; } else { if(count >= DINO_MAX_LMMIO_RESOURCES) { printk(KERN_ERR "%s is out of resource windows for range %d (0x%lx-0x%lx)\n", name, count, start, end); break; } prevres = res; res->start = start; res->end = end; res->flags = IORESOURCE_MEM; res->name = kmalloc(64, GFP_KERNEL); if(res->name) snprintf((char *)res->name, 64, "%s LMMIO %d", name, count); res++; count++; } } res = &dino_dev->hba.lmmio_space; for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) { if(res[i].flags == 0) break; result = ccio_request_resource(dino_dev->hba.dev, &res[i]); if (result < 0) { printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end); return result; } } return 0;}static int __init dino_common_init(struct parisc_device *dev, struct dino_device *dino_dev, const char *name){ int status; u32 eim; struct gsc_irq gsc_irq; struct resource *res; pcibios_register_hba(&dino_dev->hba); pci_bios = &dino_bios_ops; /* used by pci_scan_bus() */ pci_port = &dino_port_ops; /* ** Note: SMP systems can make use of IRR1/IAR1 registers ** But it won't buy much performance except in very ** specific applications/configurations. Note Dino ** still only has 11 IRQ input lines - just map some of them ** to a different processor. */ dino_dev->irq = gsc_alloc_irq(&gsc_irq); dino_dev->txn_addr = gsc_irq.txn_addr; dino_dev->txn_data = gsc_irq.txn_data; eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; /* ** Dino needs a PA "IRQ" to get a processor's attention. ** arch/parisc/kernel/irq.c returns an EIRR bit. */ if (dino_dev->irq < 0) { printk(KERN_WARNING "%s: gsc_alloc_irq() failed\n", name); return 1; } status = request_irq(dino_dev->irq, dino_isr, 0, name, dino_dev); if (status) { printk(KERN_WARNING "%s: request_irq() failed with %d\n", name, status); return 1; } /* ** Tell generic interrupt support we have 11 bits which need ** be checked in the interrupt handler. */ dino_dev->dino_region = alloc_irq_region(DINO_IRQS, &dino_irq_ops, name, dino_dev); if (NULL == dino_dev->dino_region) { printk(KERN_WARNING "%s: alloc_irq_region() failed\n", name); return 1; } /* Support the serial port which is sometimes attached on built-in * Dino / Cujo chips. */ fixup_child_irqs(dev, dino_dev->dino_region->data.irqbase, dino_choose_irq); /* ** This enables DINO to generate interrupts when it sees ** any of its inputs *change*. Just asserting an IRQ ** before it's enabled (ie unmasked) isn't good enough. */ gsc_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); /* ** Some platforms don't clear Dino's IRR0 register at boot time. ** Reading will clear it now. */ gsc_readl(dino_dev->hba.base_addr+DINO_IRR0); /* allocate I/O Port resource region */ res = &dino_dev->hba.io_space; if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) { res->name = "Dino I/O Port"; } else { res->name = "Cujo I/O Port"; } res->start = HBA_PORT_BASE(dino_dev->hba.hba_num); res->end = res->start + (HBA_PORT_SPACE_SIZE - 1); res->flags = IORESOURCE_IO; /* do not mark it busy ! */ if (request_resource(&ioport_resource, res) < 0) { printk(KERN_ERR "%s: request I/O Port region failed 0x%lx/%lx (hpa 0x%lx)\n", name, res->start, res->end, dino_dev->hba.base_addr); return 1; } return 0;}#define CUJO_RAVEN_ADDR F_EXTEND(0xf1000000UL)#define CUJO_FIREHAWK_ADDR F_EXTEND(0xf1604000UL)#define CUJO_RAVEN_BADPAGE 0x01003000UL#define CUJO_FIREHAWK_BADPAGE 0x01607000ULstatic const char *dino_vers[] = { "2.0", "2.1", "3.0", "3.1"};static const char *cujo_vers[] = { "1.0", "2.0"};void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);/*** Determine if dino should claim this chip (return 0) or not (return 1).** If so, initialize the chip appropriately (card-mode vs bridge mode).** Much of the initialization is common though.*/static int __initdino_driver_callback(struct parisc_device *dev){ struct dino_device *dino_dev; // Dino specific control struct const char *version = "unknown"; const int name_len = 32; char hw_path[64]; char *name; int is_cujo = 0; struct pci_bus *bus; name = kmalloc(name_len, GFP_KERNEL); if(name) { print_pa_hwpath(dev, hw_path); snprintf(name, name_len, "Dino [%s]", hw_path); } else name = "Dino"; if (is_card_dino(&dev->id)) { version = "3.x (card mode)"; } else { if(dev->id.hversion == 0x680) { if (dev->id.hversion_rev < 4) { version = dino_vers[dev->id.hversion_rev]; } } else { name = "Cujo"; is_cujo = 1; if (dev->id.hversion_rev < 2) { version = cujo_vers[dev->id.hversion_rev]; } } } printk("%s version %s found at 0x%lx\n", name, version, dev->hpa); if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) { printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n", dev->hpa); return 1; } /* Check for bugs */ if (is_cujo && dev->id.hversion_rev == 1) {#ifdef CONFIG_IOMMU_CCIO printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n"); if (dev->hpa == (unsigned long)CUJO_RAVEN_ADDR) { ccio_cujo20_fixup(dev->parent, CUJO_RAVEN_BADPAGE); } else if (dev->hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { ccio_cujo20_fixup(dev->parent, CUJO_FIREHAWK_BADPAGE); } else { printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa); }#endif } else if (!is_cujo && !is_card_dino(&dev->id) && dev->id.hversion_rev < 3) { printk(KERN_WARNING"The GSCtoPCI (Dino hrev %d) bus converter found may exhibit\n""data corruption. See Service Note Numbers: A4190A-01, A4191A-01.\n""Systems shipped after Aug 20, 1997 will not exhibit this problem.\n""Models affected: C180, C160, C160L, B160L, and B132L workstations.\n\n", dev->id.hversion_rev);/* REVISIT: why are C200/C240 listed in the README table but not** "Models affected"? Could be an omission in the original literature.*/ } dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL); if (!dino_dev) { printk("dino_init_chip - couldn't alloc dino_device\n"); return 1; } memset(dino_dev, 0, sizeof(struct dino_device)); dino_dev->hba.dev = dev; dino_dev->hba.base_addr = dev->hpa; /* faster access */ dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ dino_dev->dinosaur_pen = SPIN_LOCK_UNLOCKED; dino_dev->hba.iommu = ccio_get_iommu(dev); if (is_card_dino(&dev->id)) { dino_card_init(dino_dev); } else { dino_bridge_init(dino_dev, name); } if (dino_common_init(dev, dino_dev, name)) return 1; dev->dev.platform_data = dino_dev; /* ** It's not used to avoid chicken/egg problems ** with configuration accessor functions. */ bus = pci_scan_bus_parented(&dev->dev, dino_current_bus, &dino_cfg_ops, NULL); if(bus) { /* This code *depends* on scanning being single threaded * if it isn't, this global bus number count will fail */ dino_current_bus = bus->subordinate + 1; pci_bus_assign_resources(bus); } else { printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n", dev->dev.bus_id, dino_current_bus); /* increment the bus number in case of duplicates */ dino_current_bus++; } dino_dev->hba.hba_bus = bus; return 0;}/* * Normally, we would just test sversion. But the Elroy PCI adapter has * the same sversion as Dino, so we have to check hversion as well. * Unfortunately, the J2240 PDC reports the wrong hversion for the first * Dino, so we have to test for Dino, Cujo and Dino-in-a-J2240. * For card-mode Dino, most machines report an sversion of 9D. But 715 * and 725 firmware misreport it as 0x08080 for no adequately explained * reason. */static struct parisc_device_id dino_tbl[] = { { HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D },/* Card-mode Dino */ { HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x08080 }, /* XXX */ { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */ { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x682, 0xa }, /* Bridge-mode Cujo */ { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x05d, 0xa }, /* Dino in a J2240 */ { 0, }};static struct parisc_driver dino_driver = { .name = "Dino", .id_table = dino_tbl, .probe = dino_driver_callback,};/* * One time initialization to let the world know Dino is here. * This is the only routine which is NOT static. * Must be called exactly once before pci_init(). */int __init dino_init(void){ register_parisc_driver(&dino_driver); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?