⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbus.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* $Id: sbus.c,v 1.91 2000/11/08 05:04:06 davem Exp $ * sbus.c:  SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/config.h>#include <linux/init.h>#include <linux/pci.h>#include <asm/system.h>#include <asm/sbus.h>#include <asm/dma.h>#include <asm/oplib.h>#include <asm/bpp.h>#include <asm/irq.h>struct sbus_bus *sbus_root = NULL;static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };/* Perhaps when I figure out more about the iommu we'll put a * device registration routine here that probe_sbus() calls to * setup the iommu for each Sbus. *//* We call this for each SBus device, and fill the structure based * upon the prom device tree.  We return the start of memory after * the things we have allocated. *//* #define DEBUG_FILL */static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev){	unsigned long address, base;	int len;	sdev->prom_node = prom_node;	prom_getstring(prom_node, "name",		       sdev->prom_name, sizeof(sdev->prom_name));	address = prom_getint(prom_node, "address");	len = prom_getproperty(prom_node, "reg",			       (char *) sdev->reg_addrs,			       sizeof(sdev->reg_addrs));	if (len == -1) {		sdev->num_registers = 0;		goto no_regs;	}	if (len % sizeof(struct linux_prom_registers)) {		prom_printf("fill_sbus_device: proplen for regs of %s "			    " was %d, need multiple of %d\n",			    sdev->prom_name, len,			    (int) sizeof(struct linux_prom_registers));		prom_halt();	}	if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) {		prom_printf("fill_sbus_device: Too many register properties "			    "for device %s, len=%d\n",			    sdev->prom_name, len);		prom_halt();	}	sdev->num_registers = len / sizeof(struct linux_prom_registers);	sdev->ranges_applied = 0;	base = (unsigned long) sdev->reg_addrs[0].phys_addr;	if (base >= SUN_SBUS_BVADDR ||	    (sparc_cpu_model != sun4c && sparc_cpu_model != sun4)) {		/* OK, we can compute the slot number in a		 * straightforward manner.		 */		if (sparc_cpu_model == sun4u ||		    sparc_cpu_model == sun4d)			sdev->slot = sdev->reg_addrs[0].which_io;		else			sdev->slot = sbus_dev_slot(base);	} else {		int rnum;		/* Fixups are needed to compute the slot number. */		sdev->slot = sdev->reg_addrs[0].which_io;		sdev->reg_addrs[0].phys_addr =			sbus_devaddr(sdev->slot, base);		for (rnum = 1; rnum < sdev->num_registers; rnum++) {			base = (unsigned long)				sdev->reg_addrs[rnum].phys_addr;			sdev->reg_addrs[rnum].phys_addr =				sbus_devaddr(sdev->slot, base);		}	}no_regs:	len = prom_getproperty(prom_node, "ranges",			       (char *)sdev->device_ranges,			       sizeof(sdev->device_ranges));	if (len == -1) {		sdev->num_device_ranges = 0;		goto no_ranges;	}	if (len % sizeof(struct linux_prom_ranges)) {		prom_printf("fill_sbus_device: proplen for ranges of %s "			    " was %d, need multiple of %d\n",			    sdev->prom_name, len,			    (int) sizeof(struct linux_prom_ranges));		prom_halt();	}	if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {		prom_printf("fill_sbus_device: Too many range properties "			    "for device %s, len=%d\n",			    sdev->prom_name, len);		prom_halt();	}	sdev->num_device_ranges =		len / sizeof(struct linux_prom_ranges);no_ranges:	/* XXX Unfortunately, IRQ issues are very arch specific.	 * XXX Pull this crud out into an arch specific area	 * XXX at some point. -DaveM	 */#ifdef __sparc_v9__	len = prom_getproperty(prom_node, "interrupts",			       (char *) irqs, sizeof(irqs));	if (len == -1 || len == 0) {		sdev->irqs[0] = 0;		sdev->num_irqs = 0;	} else {		unsigned int pri = irqs[0].pri;		sdev->num_irqs = 1;		if (pri < 0x20)			pri += sdev->slot * 8;		sdev->irqs[0] =	sbus_build_irq(sdev->bus, pri);	}#else	len = prom_getproperty(prom_node, "intr",			       (char *)irqs, sizeof(irqs));	if (len == -1)		len = 0;	sdev->num_irqs = len / 8;	if (sdev->num_irqs == 0) {		sdev->irqs[0] = 0;	} else if (sparc_cpu_model == sun4d) {		extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);		for (len = 0; len < sdev->num_irqs; len++)			sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri);	} else {		for (len = 0; len < sdev->num_irqs; len++)			sdev->irqs[len] = irqs[len].pri;	}#endif /* !__sparc_v9__ */}/* This routine gets called from whoever needs the sbus first, to scan * the SBus device tree.  Currently it just prints out the devices * found on the bus and builds trees of SBUS structs and attached * devices. */extern void iommu_init(int iommu_node, struct sbus_bus *sbus);extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);void sun4_init(void);#ifdef CONFIG_SUN_AUXIOextern void auxio_probe(void);#endifstatic void __init sbus_do_child_siblings(int start_node,					  struct sbus_dev *child,					  struct sbus_dev *parent,					  struct sbus_bus *sbus){	struct sbus_dev *this_dev = child;	int this_node = start_node;	/* Child already filled in, just need to traverse siblings. */	child->child = NULL;	child->parent = parent;	while((this_node = prom_getsibling(this_node)) != 0) {		this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);		this_dev = this_dev->next;		this_dev->next = 0;		this_dev->parent = parent;		this_dev->bus = sbus;		fill_sbus_device(this_node, this_dev);		if(prom_getchild(this_node)) {			this_dev->child = kmalloc(sizeof(struct sbus_dev),						  GFP_ATOMIC);			this_dev->child->bus = sbus;			this_dev->child->next = 0;			fill_sbus_device(prom_getchild(this_node), this_dev->child);			sbus_do_child_siblings(prom_getchild(this_node),					       this_dev->child, this_dev, sbus);		} else {			this_dev->child = NULL;		}	}}/* * XXX This functions appears to be a distorted version of * prom_sbus_ranges_init(), with all sun4d stuff cut away. * Ask DaveM what is going on here, how is sun4d supposed to work... XXX */static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus){	int len;	len = prom_getproperty(sbus->prom_node, "ranges",			       (char *) sbus->sbus_ranges,			       sizeof(sbus->sbus_ranges));	if (len == -1 || len == 0) {		sbus->num_sbus_ranges = 0;		return;	}	sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges);}static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,					  int num_ranges,					  struct linux_prom_registers *regs,					  int num_regs){	if (num_ranges) {		int regnum;		for (regnum = 0; regnum < num_regs; regnum++) {			int rngnum;			for (rngnum = 0; rngnum < num_ranges; rngnum++) {				if (regs[regnum].which_io == ranges[rngnum].ot_child_space)					break;			}			if (rngnum == num_ranges) {				prom_printf("sbus_apply_ranges: Cannot find matching "					    "range nregs[%d] nranges[%d].\n",					    num_regs, num_ranges);				prom_halt();			}			regs[regnum].which_io = ranges[rngnum].ot_parent_space;			regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;		}	}}static void __init __fixup_regs_sdev(struct sbus_dev *sdev){	if (sdev->num_registers != 0) {		struct sbus_dev *parent = sdev->parent;		int i;		while (parent != NULL) {			__apply_ranges_to_regs(parent->device_ranges,					       parent->num_device_ranges,					       sdev->reg_addrs,					       sdev->num_registers);			parent = parent->parent;		}		__apply_ranges_to_regs(sdev->bus->sbus_ranges,				       sdev->bus->num_sbus_ranges,				       sdev->reg_addrs,				       sdev->num_registers);		for (i = 0; i < sdev->num_registers; i++) {			struct resource *res = &sdev->resource[i];			res->start = sdev->reg_addrs[i].phys_addr;			res->end = (res->start +				    (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);			res->flags = IORESOURCE_IO |				(sdev->reg_addrs[i].which_io & 0xff);		}	}}static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev){	struct sbus_dev *sdev;	for (sdev = first_sdev; sdev; sdev = sdev->next) {		if (sdev->child)			sbus_fixup_all_regs(sdev->child);		__fixup_regs_sdev(sdev);	}}extern void register_proc_sparc_ioport(void);void __init sbus_init(void){	int nd, this_sbus, sbus_devs, topnd, iommund;	unsigned int sbus_clock;	struct sbus_bus *sbus;	struct sbus_dev *this_dev;	int num_sbus = 0;  /* How many did we find? */#ifndef __sparc_v9__	register_proc_sparc_ioport();#endif#ifdef CONFIG_SUN4	return sun4_dvma_init();#endif	topnd = prom_getchild(prom_root_node);		/* Finding the first sbus is a special case... */	iommund = 0;	if(sparc_cpu_model == sun4u) {		nd = prom_searchsiblings(topnd, "sbus");		if(nd == 0) {#ifdef CONFIG_PCI			if (!pcibios_present()) {					prom_printf("Neither SBUS nor PCI found.\n");				prom_halt();			} else {#ifdef __sparc_v9__				extern void firetruck_init(void);				firetruck_init();#endif			}			return;#else			prom_printf("YEEE, UltraSparc sbus not found\n");			prom_halt();#endif		}	} else if(sparc_cpu_model == sun4d) {		if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||		   (nd = prom_getchild(iommund)) == 0 ||		   (nd = prom_searchsiblings(nd, "sbi")) == 0) {		   	panic("sbi not found");		}	} else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {		if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||		   (nd = prom_getchild(iommund)) == 0 ||		   (nd = prom_searchsiblings(nd, "sbus")) == 0) {#ifdef CONFIG_PCI                        if (!pcibios_present()) {                                       prom_printf("Neither SBUS nor PCI found.\n");                                prom_halt();                        }                        return;#else			/* No reason to run further - the data access trap will occur. */			panic("sbus not found");#endif		}	}	/* Ok, we've found the first one, allocate first SBus struct	 * and place in chain.	 */	sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);	sbus->next = NULL;	sbus->prom_node = nd;	this_sbus = nd;	if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d)		iommu_init(iommund, sbus);	/* Loop until we find no more SBUS's */	while(this_sbus) {#ifdef __sparc_v9__						  		/* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */		if(sparc_cpu_model == sun4u) {			extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus);			sbus_iommu_init(this_sbus, sbus);		}#endif#ifndef __sparc_v9__						  		if (sparc_cpu_model == sun4d)			iounit_init(this_sbus, iommund, sbus);#endif						   		printk("sbus%d: ", num_sbus);		sbus_clock = prom_getint(this_sbus, "clock-frequency");		if(sbus_clock == -1)			sbus_clock = (25*1000*1000);		printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),		       (int) (((sbus_clock/1000)%1000 != 0) ? 			      (((sbus_clock/1000)%1000) + 1000) : 0));		prom_getstring(this_sbus, "name",			       sbus->prom_name, sizeof(sbus->prom_name));		sbus->clock_freq = sbus_clock;#ifndef __sparc_v9__				if (sparc_cpu_model == sun4d) {			sbus->devid = prom_getint(iommund, "device-id");			sbus->board = prom_getint(iommund, "board#");		}#endif				sbus_bus_ranges_init(iommund, sbus);		sbus_devs = prom_getchild(this_sbus);		sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);		this_dev = sbus->devices;		this_dev->next = NULL;		this_dev->bus = sbus;		this_dev->parent = NULL;		fill_sbus_device(sbus_devs, this_dev);		/* Should we traverse for children? */		if(prom_getchild(sbus_devs)) {			/* Allocate device node */			this_dev->child = kmalloc(sizeof(struct sbus_dev),						  GFP_ATOMIC);			/* Fill it */			this_dev->child->bus = sbus;			this_dev->child->next = 0;			fill_sbus_device(prom_getchild(sbus_devs),					 this_dev->child);			sbus_do_child_siblings(prom_getchild(sbus_devs),					       this_dev->child,					       this_dev,					       sbus);		} else {			this_dev->child = NULL;		}		while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {			/* Allocate device node */			this_dev->next = kmalloc(sizeof(struct sbus_dev),						 GFP_ATOMIC);			this_dev = this_dev->next;			this_dev->next = NULL;			/* Fill it */			this_dev->bus = sbus;			this_dev->parent = NULL;			fill_sbus_device(sbus_devs, this_dev);			/* Is there a child node hanging off of us? */			if(prom_getchild(sbus_devs)) {				/* Get new device struct */				this_dev->child = kmalloc(sizeof(struct sbus_dev),							  GFP_ATOMIC);				/* Fill it */				this_dev->child->bus = sbus;				this_dev->child->next = 0;				fill_sbus_device(prom_getchild(sbus_devs),						 this_dev->child);				sbus_do_child_siblings(prom_getchild(sbus_devs),						       this_dev->child,						       this_dev,						       sbus);			} else {				this_dev->child = NULL;			}		}		/* Walk all devices and apply parent ranges. */		sbus_fixup_all_regs(sbus->devices);		dvma_init(sbus);		num_sbus++;		if(sparc_cpu_model == sun4u) {			this_sbus = prom_getsibling(this_sbus);			if(!this_sbus)				break;			this_sbus = prom_searchsiblings(this_sbus, "sbus");		} else if(sparc_cpu_model == sun4d) {			iommund = prom_getsibling(iommund);			if(!iommund)				break;			iommund = prom_searchsiblings(iommund, "io-unit");			if(!iommund)				break;			this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");		} else {			this_sbus = prom_getsibling(this_sbus);			if(!this_sbus)				break;			this_sbus = prom_searchsiblings(this_sbus, "sbus");		}		if(this_sbus) {			sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);			sbus = sbus->next;			sbus->next = NULL;			sbus->prom_node = this_sbus;		} else {			break;		}	} /* while(this_sbus) */	if (sparc_cpu_model == sun4d) {		extern void sun4d_init_sbi_irq(void);		sun4d_init_sbi_irq();	}	#ifdef __sparc_v9__	if (sparc_cpu_model == sun4u) {		extern void firetruck_init(void);		firetruck_init();	}#endif#ifdef CONFIG_SUN_AUXIO	if (sparc_cpu_model == sun4u)		auxio_probe ();#endif#ifdef __sparc_v9__	if (sparc_cpu_model == sun4u) {		extern void clock_probe(void);		clock_probe();	}#endif}

⌨️ 快捷键说明

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