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 + -
显示快捷键?