ebus.c

来自「linux 内核源代码」· C语言 代码 · 共 393 行

C
393
字号
/* $Id: ebus.c,v 1.20 2002/01/05 01:13:43 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be) * * Adopted for sparc by V. Roganov and G. Raiko. * Fixes for different platforms by Pete Zaitcev. */#include <linux/kernel.h>#include <linux/types.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/string.h>#include <asm/system.h>#include <asm/page.h>#include <asm/pbm.h>#include <asm/ebus.h>#include <asm/io.h>#include <asm/oplib.h>#include <asm/prom.h>#include <asm/bpp.h>struct linux_ebus *ebus_chain = NULL;/* We are together with pcic.c under CONFIG_PCI. */extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);/* * IRQ Blacklist * Here we list PROMs and systems that are known to supply crap as IRQ numbers. */struct ebus_device_irq {	char *name;	unsigned int pin;};struct ebus_system_entry {	char *esname;	struct ebus_device_irq *ipt;};static struct ebus_device_irq je1_1[] = {	{ "8042",		 3 },	{ "SUNW,CS4231",	 0 },	{ "parallel",		 0 },	{ "se",			 2 },	{ NULL, 0 }};/* * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32). * Blacklist the sucker... Note that Gleb's system will work. */static struct ebus_system_entry ebus_blacklist[] = {	{ "SUNW,JavaEngine1", je1_1 },	{ NULL, NULL }};static struct ebus_device_irq *ebus_blackp = NULL;/* */static inline unsigned long ebus_alloc(size_t size){	return (unsigned long)kmalloc(size, GFP_ATOMIC);}/* */int __init ebus_blacklist_irq(const char *name){	struct ebus_device_irq *dp;	if ((dp = ebus_blackp) != NULL) {		for (; dp->name != NULL; dp++) {			if (strcmp(name, dp->name) == 0) {				return pcic_pin_to_irq(dp->pin, name);			}		}	}	return 0;}void __init fill_ebus_child(struct device_node *dp,			    struct linux_ebus_child *dev){	const int *regs;	const int *irqs;	int i, len;	dev->prom_node = dp;	regs = of_get_property(dp, "reg", &len);	if (!regs)		len = 0;	dev->num_addrs = len / sizeof(regs[0]);	for (i = 0; i < dev->num_addrs; i++) {		if (regs[i] >= dev->parent->num_addrs) {			prom_printf("UGH: property for %s was %d, need < %d\n",				    dev->prom_node->name, len,				    dev->parent->num_addrs);			panic(__FUNCTION__);		}		/* XXX resource */		dev->resource[i].start =			dev->parent->resource[regs[i]].start;	}	for (i = 0; i < PROMINTR_MAX; i++)		dev->irqs[i] = PCI_IRQ_NONE;	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {		dev->num_irqs = 1;	} else {		irqs = of_get_property(dp, "interrupts", &len);		if (!irqs) {			dev->num_irqs = 0;			dev->irqs[0] = 0;			if (dev->parent->num_irqs != 0) {				dev->num_irqs = 1;				dev->irqs[0] = dev->parent->irqs[0];			}		} else {			dev->num_irqs = len / sizeof(irqs[0]);			if (irqs[0] == 0 || irqs[0] >= 8) {				/*				 * XXX Zero is a valid pin number...				 * This works as long as Ebus is not wired				 * to INTA#.				 */				printk("EBUS: %s got bad irq %d from PROM\n",				       dev->prom_node->name, irqs[0]);				dev->num_irqs = 0;				dev->irqs[0] = 0;			} else {				dev->irqs[0] =					pcic_pin_to_irq(irqs[0],							dev->prom_node->name);			}		}	}}void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev){	const struct linux_prom_registers *regs;	struct linux_ebus_child *child;	struct dev_archdata *sd;	const int *irqs;	int i, n, len;	unsigned long baseaddr;	dev->prom_node = dp;	regs = of_get_property(dp, "reg", &len);	if (!regs)		len = 0;	if (len % sizeof(struct linux_prom_registers)) {		prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",			    dev->prom_node->name, len,			    (int)sizeof(struct linux_prom_registers));		panic(__FUNCTION__);	}	dev->num_addrs = len / sizeof(struct linux_prom_registers);	for (i = 0; i < dev->num_addrs; i++) {		/*		 * XXX Collect JE-1 PROM		 * 		 * Example - JS-E with 3.11:		 *  /ebus		 *      regs 		 *        0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,		 *        0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,		 *        0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,		 *      ranges		 *        0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,		 *        0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,		 *  /ebus/8042		 *      regs		 *        0x00000001, 0x00300060, 0x00000008,		 *        0x00000001, 0x00300060, 0x00000008,		 */		n = regs[i].which_io;		if (n >= 4) {			/* XXX This is copied from old JE-1 by Gleb. */			n = (regs[i].which_io - 0x10) >> 2;		} else {			;		}/* * XXX Now as we have regions, why don't we make an on-demand allocation... */		dev->resource[i].start = 0;		if ((baseaddr = dev->bus->self->resource[n].start +		    regs[i].phys_addr) != 0) {			/* dev->resource[i].name = dev->prom_name; */			if ((baseaddr = (unsigned long) ioremap(baseaddr,			    regs[i].reg_size)) == 0) {				panic("ebus: unable to remap dev %s",				      dev->prom_node->name);			}		}		dev->resource[i].start = baseaddr;	/* XXX Unaligned */	}	for (i = 0; i < PROMINTR_MAX; i++)		dev->irqs[i] = PCI_IRQ_NONE;	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {		dev->num_irqs = 1;	} else {		irqs = of_get_property(dp, "interrupts", &len);		if (!irqs) {			dev->num_irqs = 0;			if ((dev->irqs[0] = dev->bus->self->irq) != 0) {				dev->num_irqs = 1;/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */			}		} else {			dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */			if (irqs[0] == 0 || irqs[0] >= 8) {				/* See above for the parent. XXX */				printk("EBUS: %s got bad irq %d from PROM\n",				       dev->prom_node->name, irqs[0]);				dev->num_irqs = 0;				dev->irqs[0] = 0;			} else {				dev->irqs[0] =					pcic_pin_to_irq(irqs[0],							dev->prom_node->name);			}		}	}	sd = &dev->ofdev.dev.archdata;	sd->prom_node = dp;	sd->op = &dev->ofdev;	sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;	dev->ofdev.node = dp;	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;	dev->ofdev.dev.bus = &ebus_bus_type;	sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);	/* Register with core */	if (of_device_register(&dev->ofdev) != 0)		printk(KERN_DEBUG "ebus: device registration error for %s!\n",		       dp->path_component_name);	if ((dp = dp->child) != NULL) {		dev->children = (struct linux_ebus_child *)			ebus_alloc(sizeof(struct linux_ebus_child));		child = dev->children;		child->next = NULL;		child->parent = dev;		child->bus = dev->bus;		fill_ebus_child(dp, child);		while ((dp = dp->sibling) != NULL) {			child->next = (struct linux_ebus_child *)				ebus_alloc(sizeof(struct linux_ebus_child));			child = child->next;			child->next = NULL;			child->parent = dev;			child->bus = dev->bus;			fill_ebus_child(dp, child);		}	}}void __init ebus_init(void){	const struct linux_prom_pci_registers *regs;	struct linux_pbm_info *pbm;	struct linux_ebus_device *dev;	struct linux_ebus *ebus;	struct ebus_system_entry *sp;	struct pci_dev *pdev;	struct pcidev_cookie *cookie;	struct device_node *dp;	struct resource *p;	unsigned short pci_command;	int len, reg, nreg;	int num_ebus = 0;	dp = of_find_node_by_path("/");	for (sp = ebus_blacklist; sp->esname != NULL; sp++) {		if (strcmp(dp->name, sp->esname) == 0) {			ebus_blackp = sp->ipt;			break;		}	}	pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);	if (!pdev)		return;	cookie = pdev->sysdata;	dp = cookie->prom_node;	ebus_chain = ebus = (struct linux_ebus *)			ebus_alloc(sizeof(struct linux_ebus));	ebus->next = NULL;	while (dp) {		struct device_node *nd;		ebus->prom_node = dp;		ebus->self = pdev;		ebus->parent = pbm = cookie->pbm;		/* Enable BUS Master. */		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);		pci_command |= PCI_COMMAND_MASTER;		pci_write_config_word(pdev, PCI_COMMAND, pci_command);		regs = of_get_property(dp, "reg", &len);		if (!regs) {			prom_printf("%s: can't find reg property\n",				    __FUNCTION__);			prom_halt();		}		nreg = len / sizeof(struct linux_prom_pci_registers);		p = &ebus->self->resource[0];		for (reg = 0; reg < nreg; reg++) {			if (!(regs[reg].which_io & 0x03000000))				continue;			(p++)->start = regs[reg].phys_lo;		}		ebus->ofdev.node = dp;		ebus->ofdev.dev.parent = &pdev->dev;		ebus->ofdev.dev.bus = &ebus_bus_type;		sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);		/* Register with core */		if (of_device_register(&ebus->ofdev) != 0)			printk(KERN_DEBUG "ebus: device registration error for %s!\n",			       dp->path_component_name);		nd = dp->child;		if (!nd)			goto next_ebus;		ebus->devices = (struct linux_ebus_device *)				ebus_alloc(sizeof(struct linux_ebus_device));		dev = ebus->devices;		dev->next = NULL;		dev->children = NULL;		dev->bus = ebus;		fill_ebus_device(nd, dev);		while ((nd = nd->sibling) != NULL) {			dev->next = (struct linux_ebus_device *)				ebus_alloc(sizeof(struct linux_ebus_device));			dev = dev->next;			dev->next = NULL;			dev->children = NULL;			dev->bus = ebus;			fill_ebus_device(nd, dev);		}	next_ebus:		pdev = pci_get_device(PCI_VENDOR_ID_SUN,				       PCI_DEVICE_ID_SUN_EBUS, pdev);		if (!pdev)			break;		cookie = pdev->sysdata;		dp = cookie->prom_node;		ebus->next = (struct linux_ebus *)			ebus_alloc(sizeof(struct linux_ebus));		ebus = ebus->next;		ebus->next = NULL;		++num_ebus;	}	if (pdev)		pci_dev_put(pdev);}

⌨️ 快捷键说明

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