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

📄 lba_pci.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** make range information from PDC available to PCI subsystem.** We make the PDC call here in order to get the PCI bus range** numbers. The rest will get forwarded in pcibios_fixup_bus().** We don't have a struct pci_bus assigned to us yet.*/static voidlba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev){	unsigned long bytecnt;	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;	/* PA_VIEW */	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;	/* IO_VIEW */	long io_count;	long status;	/* PDC return status */	long pa_count;	int i;	/* return cell module (IO view) */	status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,				PA_VIEW, & pa_pdc_cell);	pa_count = pa_pdc_cell.mod[1];	status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,				IO_VIEW, &io_pdc_cell);	io_count = io_pdc_cell.mod[1];	/* We've already done this once for device discovery...*/	if (status != PDC_OK) {		panic("pdc_pat_cell_module() call failed for LBA!\n");	}	if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) {		panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n");	}	/*	** Inspect the resources PAT tells us about	*/	for (i = 0; i < pa_count; i++) {		struct {			unsigned long type;			unsigned long start;			unsigned long end;	/* aka finish */		} *p, *io;		struct resource *r;		p = (void *) &(pa_pdc_cell.mod[2+i*3]);		io = (void *) &(io_pdc_cell.mod[2+i*3]);		/* Convert the PAT range data to PCI "struct resource" */		switch(p->type & 0xff) {		case PAT_PBNUM:			lba_dev->hba.bus_num.start = p->start;			lba_dev->hba.bus_num.end   = p->end;			break;		case PAT_LMMIO:			/* used to fix up pre-initialized MEM BARs */			lba_dev->hba.lmmio_space_offset = p->start - io->start;			r = &(lba_dev->hba.lmmio_space);			r->name   = "LBA LMMIO";			r->start  = p->start;			r->end    = p->end;			r->flags  = IORESOURCE_MEM;			r->parent = r->sibling = r->child = NULL;			break;		case PAT_GMMIO:			printk(KERN_WARNING MODULE_NAME				" range[%d] : ignoring GMMIO (0x%lx)\n",				i, p->start);			lba_dev->gmmio_base = p->start;			break;		case PAT_NPIOP:			printk(KERN_WARNING MODULE_NAME				" range[%d] : ignoring NPIOP (0x%lx)\n",				i, p->start);			break;		case PAT_PIOP:			/*			** Postable I/O port space is per PCI host adapter.			*/			/* save base of 64MB PIOP region */			lba_dev->iop_base = p->start;			r = &(lba_dev->hba.io_space);			r->name   = "LBA I/O Port";			r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);			r->end    = r->start + HBA_PORT_SPACE_SIZE - 1;			r->flags  = IORESOURCE_IO;			r->parent = r->sibling = r->child = NULL;			break;		default:			printk(KERN_WARNING MODULE_NAME				" range[%d] : unknown pat range type (0x%lx)\n",				i, p->type & 0xff);			break;		}	}}#endif	/* __LP64__ */static voidlba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev){	struct resource *r;	unsigned long rsize;	int lba_num;#ifdef __LP64__	/*	** Sign extend all BAR values on "legacy" platforms.	** "Sprockets" PDC (Forte/Allegro) initializes everything	** for "legacy" 32-bit OS (HPUX 10.20).	** Upper 32-bits of 64-bit BAR will be zero too.	*/	lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL;#else	lba_dev->hba.lmmio_space_offset = 0UL;#endif	/*	** With "legacy" firmware, the lowest byte of FW_SCRATCH	** represents bus->secondary and the second byte represents	** bus->subsidiary (i.e. highest PPB programmed by firmware).	** PCI bus walk *should* end up with the same result.	** FIXME: But we don't have sanity checks in PCI or LBA.	*/	lba_num = READ_REG32(pa_dev->hpa + LBA_FW_SCRATCH);	r = &(lba_dev->hba.bus_num);	r->name = "LBA PCI Busses";	r->start = lba_num & 0xff;	r->end = (lba_num>>8) & 0xff;	/* Set up local PCI Bus resources - we don't really need	** them for Legacy boxes but it's nice to see in /proc.	*/	r = &(lba_dev->hba.lmmio_space);	r->name  = "LBA PCI LMMIO";	r->flags = IORESOURCE_MEM;	/* Ignore "Range Enable" bit in the BASE register */	r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),		((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL);	rsize =  ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1;	/*	** Each rope only gets part of the distributed range.	** Adjust "window" for this rope	*/	rsize /= ROPES_PER_SBA;	r->start += rsize * LBA_NUM(pa_dev->hpa);	r->end = r->start + rsize - 1 ;	/*	** XXX FIXME - ignore LBA_ELMMIO_BASE for now	** "Directed" ranges are used when the "distributed range" isn't	** sufficient for all devices below a given LBA.  Typically devices	** like graphics cards or X25 may need a directed range when the	** bus has multiple slots (ie multiple devices) or the device	** needs more than the typical 4 or 8MB a distributed range offers.	**	** The main reason for ignoring it now frigging complications.	** Directed ranges may overlap (and have precedence) over	** distributed ranges. Ie a distributed range assigned to a unused	** rope may be used by a directed range on a different rope.	** Support for graphics devices may require fixing this	** since they may be assigned a directed range which overlaps	** an existing (but unused portion of) distributed range.	*/	r = &(lba_dev->hba.elmmio_space);	r->name  = "extra LBA PCI LMMIO";	r->flags = IORESOURCE_MEM;	r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);	r->end   = 0;	/* check Range Enable bit */	if (r->start & 1) {		/* First baby step to getting Direct Ranges listed in /proc.		** AFAIK, only Sprockets PDC will setup a directed Range.		*/		r->start &= ~1;		r->end    = r->start;		r->end   += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);		printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx  SIZE 0x%lx\n",			r->start,			r->end + 1);	}	r = &(lba_dev->hba.io_space);	r->name  = "LBA PCI I/O Ports";	r->flags = IORESOURCE_IO;	r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L;	r->end   = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));	/* Virtualize the I/O Port space ranges */	lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num);	r->start |= lba_num;	r->end   |= lba_num;}/******************************************************************************   LBA initialization code (HW and SW)****   o identify LBA chip itself**   o initialize LBA chip modes (HardFail)**   o FIXME: initialize DMA hints for reasonable defaults**   o enable configuration functions**   o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked)****************************************************************************/static int __initlba_hw_init(struct lba_device *d){	u32 stat;	u32 bus_reset;	/* PDC_PAT_BUG */#if 0	printk(KERN_DEBUG "LBA %lx  STAT_CTL %Lx  ERROR_CFG %Lx  STATUS %Lx DMA_CTL %Lx\n",		d->hba.base_addr,		READ_REG64(d->hba.base_addr + LBA_STAT_CTL),		READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG),		READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS),		READ_REG64(d->hba.base_addr + LBA_DMA_CTL) );	printk(KERN_DEBUG "	ARB mask %Lx  pri %Lx  mode %Lx  mtlt %Lx\n",		READ_REG64(d->hba.base_addr + LBA_ARB_MASK),		READ_REG64(d->hba.base_addr + LBA_ARB_PRI),		READ_REG64(d->hba.base_addr + LBA_ARB_MODE),		READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) );	printk(KERN_DEBUG "	HINT cfg 0x%Lx\n",		READ_REG64(d->hba.base_addr + LBA_HINT_CFG));	printk(KERN_DEBUG "	HINT reg ");	{ int i;	for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8)		printk(" %Lx", READ_REG64(d->hba.base_addr + i));	}	printk("\n");#endif	/* DEBUG_LBA_PAT */#ifdef __LP64__#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support#endif	/* PDC_PAT_BUG: exhibited in rev 40.48  on L2000 */	bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1;	if (bus_reset) {		printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n");	}	stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);	if (stat & LBA_SMART_MODE) {		printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n");		stat &= ~LBA_SMART_MODE;		WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);	}	/* Set HF mode as the default (vs. -1 mode). */        stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);	WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);	/*	** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal	** if it's not already set. If we just cleared the PCI Bus Reset	** signal, wait a bit for the PCI devices to recover and setup.	*/	if (bus_reset)		mdelay(pci_post_reset_delay);	if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) {		/*		** PDC_PAT_BUG: PDC rev 40.48 on L2000.		** B2000/C3600/J6000 also have this problem?		** 		** Elroys with hot pluggable slots don't get configured		** correctly if the slot is empty.  ARB_MASK is set to 0		** and we can't master transactions on the bus if it's		** not at least one. 0x3 enables elroy and first slot.		*/		printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n");		WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK);	}	/*	** FIXME: Hint registers are programmed with default hint	** values by firmware. Hints should be sane even if we	** can't reprogram them the way drivers want.	*/	return 0;}static void __initlba_common_init(struct lba_device *lba_dev){	pci_bios = &lba_bios_ops;	pcibios_register_hba(HBA_DATA(lba_dev));	lba_dev->lba_lock = SPIN_LOCK_UNLOCKED;		/*	** Set flags which depend on hw_rev	*/	if (!LBA_TR4PLUS(lba_dev)) {		lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG;	}}/*** Determine if lba should claim this chip (return 0) or not (return 1).** If so, initialize the chip and tell other partners in crime they** have work to do.*/static int __initlba_driver_callback(struct parisc_device *dev){	struct lba_device *lba_dev;	struct pci_bus *lba_bus;	u32 func_class;	void *tmp_obj;	char *version;	/* Read HW Rev First */	func_class = READ_REG32(dev->hpa + LBA_FCLASS);	func_class &= 0xf;	switch (func_class) {	case 0:	version = "TR1.0"; break;	case 1:	version = "TR2.0"; break;	case 2:	version = "TR2.1"; break;	case 3:	version = "TR2.2"; break;	case 4:	version = "TR3.0"; break;	case 5:	version = "TR4.0"; break;	default: version = "TR4+";	}	printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",		MODULE_NAME, version, func_class & 0xf, dev->hpa);	/* Just in case we find some prototypes... */	if (func_class < 2) {		printk(KERN_WARNING "Can't support LBA older than TR2.1 "			"- continuing under adversity.\n");	}	/*	** Tell I/O SAPIC driver we have a IRQ handler/region.	*/	tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE);	/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't	**	have an IRT entry will get NULL back from iosapic code.	*/		lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);	if (NULL == lba_dev)	{		printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");		return(1);	}	memset(lba_dev, 0, sizeof(struct lba_device));	/* ---------- First : initialize data we already have --------- */	/*	** Need hw_rev to adjust configuration space behavior.	** LBA_TR4PLUS macro uses hw_rev field.	*/	lba_dev->hw_rev = func_class;	lba_dev->hba.base_addr = dev->hpa;  /* faster access */	lba_dev->hba.dev = dev;	lba_dev->iosapic_obj = tmp_obj;  /* save interrupt handle */	lba_dev->hba.iommu = sba_get_iommu(dev);  /* get iommu data */	/* ------------ Second : initialize common stuff ---------- */	lba_common_init(lba_dev);	if (lba_hw_init(lba_dev))		return(1);	/* ---------- Third : setup I/O Port and MMIO resources  --------- */#ifdef __LP64__	if (is_pdc_pat()) {		/* PDC PAT firmware uses PIOP region of GMMIO space. */		pci_port = &lba_pat_port_ops;		/* Go ask PDC PAT what resources this LBA has */		lba_pat_resources(dev, lba_dev);	} else#endif	{		/* Sprockets PDC uses NPIOP region */		pci_port = &lba_astro_port_ops;		/* Poke the chip a bit for /proc output */		lba_legacy_resources(dev, lba_dev);	}	/* 	** Tell PCI support another PCI bus was found.	** Walks PCI bus for us too.	*/	lba_bus = lba_dev->hba.hba_bus =		pci_scan_bus(lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);#ifdef __LP64__	if (is_pdc_pat()) {		/* assign resources to un-initialized devices */		DBG_PAT("LBA pcibios_assign_unassigned_resources()\n");		pcibios_assign_unassigned_resources(lba_bus);#ifdef DEBUG_LBA_PAT		DBG_PAT("\nLBA PIOP resource tree\n");		lba_dump_res(&lba_dev->hba.io_space, 2);		DBG_PAT("\nLBA LMMIO resource tree\n");		lba_dump_res(&lba_dev->hba.lmmio_space, 2);#endif	}#endif	/*	** Once PCI register ops has walked the bus, access to config	** space is restricted. Avoids master aborts on config cycles.	** Early LBA revs go fatal on *any* master abort.	*/	if (!LBA_TR4PLUS(lba_dev)) {		lba_dev->flags |= LBA_FLAG_SKIP_PROBE;	}	/* Whew! Finally done! Tell services we got this one covered. */	return 0;}static struct parisc_device_id lba_tbl[] = {	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x782, 0xa },	{ 0, }};static struct parisc_driver lba_driver = {	name:		MODULE_NAME,	id_table:	lba_tbl,	probe:		lba_driver_callback};/*** One time initialization to let the world know the LBA was found.** Must be called exactly once before pci_init().*/void __init lba_init(void){	register_parisc_driver(&lba_driver);}/*** Initialize the IBASE/IMASK registers for LBA (Elroy).** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA).** sba_iommu is responsible for locking (none needed at init time).*/voidlba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask){	unsigned long base_addr = lba->hpa;	imask <<= 2;	/* adjust for hints - 2 more bits */	ASSERT((ibase & 0x003fffff) == 0);	ASSERT((imask & 0x003fffff) == 0);		DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);	WRITE_REG32( imask, base_addr + LBA_IMASK);	WRITE_REG32( ibase, base_addr + LBA_IBASE);}

⌨️ 快捷键说明

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