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

📄 pci_sabre.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		prom_halt();	}	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO);	if (request_irq(irq, sabre_pcierr_intr,			SA_SHIRQ, "SABRE PCIERR", p) < 0) {		prom_printf("SABRE%d: Cannot register PciERR interrupt.\n",			    p->index);		prom_halt();	}	tmp = sabre_read(base + SABRE_PCICTRL);	tmp |= SABRE_PCICTRL_ERREN;	sabre_write(base + SABRE_PCICTRL, tmp);}static void __init sabre_resource_adjust(struct pci_dev *pdev,					 struct resource *res,					 struct resource *root){	struct pcidev_cookie *pcp = pdev->sysdata;	struct pci_controller_info *p = pcp->pbm->parent;	unsigned long base;	if (res->flags & IORESOURCE_IO)		base = p->controller_regs + SABRE_IOSPACE;	else		base = p->controller_regs + SABRE_MEMSPACE;	res->start += base;	res->end += base;}static void __init sabre_base_address_update(struct pci_dev *pdev, int resource){	struct pcidev_cookie *pcp = pdev->sysdata;	struct pci_pbm_info *pbm = pcp->pbm;	struct pci_controller_info *p = pbm->parent;	struct resource *res;	unsigned long base;	u32 reg;	int where, size, is_64bit;	res = &pdev->resource[resource];	where = PCI_BASE_ADDRESS_0 + (resource * 4);	is_64bit = 0;	if (res->flags & IORESOURCE_IO)		base = p->controller_regs + SABRE_IOSPACE;	else {		base = p->controller_regs + SABRE_MEMSPACE;		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)		    == PCI_BASE_ADDRESS_MEM_TYPE_64)			is_64bit = 1;	}	size = res->end - res->start;	pci_read_config_dword(pdev, where, &reg);	reg = ((reg & size) |	       (((u32)(res->start - base)) & ~size));	pci_write_config_dword(pdev, where, reg);	/* This knows that the upper 32-bits of the address	 * must be zero.  Our PCI common layer enforces this.	 */	if (is_64bit)		pci_write_config_dword(pdev, where + 4, 0);}static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus){	struct list_head *walk = &sabre_bus->devices;	for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) {		struct pci_dev *pdev = pci_dev_b(walk);		if (pdev->vendor == PCI_VENDOR_ID_SUN &&		    pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {			u16 word;			sabre_read_word(pdev, PCI_COMMAND, &word);			word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |				PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |				PCI_COMMAND_IO;			sabre_write_word(pdev, PCI_COMMAND, word);			/* Status register bits are "write 1 to clear". */			sabre_write_word(pdev, PCI_STATUS, 0xffff);			sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff);			/* Use a primary/seconday latency timer value			 * of 64.			 */			sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);			sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);			/* Enable reporting/forwarding of master aborts,			 * parity, and SERR.			 */			sabre_write_byte(pdev, PCI_BRIDGE_CONTROL,					 (PCI_BRIDGE_CTL_PARITY |					  PCI_BRIDGE_CTL_SERR |					  PCI_BRIDGE_CTL_MASTER_ABORT));		}	}}static void __init sabre_scan_bus(struct pci_controller_info *p){	static int once = 0;	struct pci_bus *sabre_bus;	struct list_head *walk;	/* The APB bridge speaks to the Sabre host PCI bridge	 * at 66Mhz, but the front side of APB runs at 33Mhz	 * for both segments.	 */	p->pbm_A.is_66mhz_capable = 0;	p->pbm_B.is_66mhz_capable = 0;	/* Unlike for PSYCHO, we can only have one SABRE	 * in a system.  Having multiple SABREs is thus	 * and error, and as a consequence we do not need	 * to do any bus renumbering but we do have to have	 * the pci_bus2pbm array setup properly.	 *	 * Also note that the SABRE host bridge is hardwired	 * to live at bus 0.	 */	if (once != 0) {		prom_printf("SABRE: Multiple controllers unsupported.\n");		prom_halt();	}	once++;	/* The pci_bus2pbm table has already been setup in sabre_init. */	sabre_bus = pci_scan_bus(p->pci_first_busno,				 p->pci_ops,				 &p->pbm_A);	apb_init(p, sabre_bus);	walk = &sabre_bus->children;	for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) {		struct pci_bus *pbus = pci_bus_b(walk);		struct pci_pbm_info *pbm;		if (pbus->number == p->pbm_A.pci_first_busno) {			pbm = &p->pbm_A;		} else if (pbus->number == p->pbm_B.pci_first_busno) {			pbm = &p->pbm_B;		} else			continue;		pbus->sysdata = pbm;		pbm->pci_bus = pbus;		pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node);		pci_record_assignments(pbm, pbus);		pci_assign_unassigned(pbm, pbus);		pci_fixup_irq(pbm, pbus);		pci_determine_66mhz_disposition(pbm, pbus);		pci_setup_busmastering(pbm, pbus);	}	sabre_register_error_handlers(p);}static void __init sabre_iommu_init(struct pci_controller_info *p,				    int tsbsize, unsigned long dvma_offset,				    u32 dma_mask){	unsigned long tsbbase, i, order;	u64 control;	/* Setup initial software IOMMU state. */	spin_lock_init(&p->iommu.lock);	p->iommu.iommu_cur_ctx = 0;	/* Register addresses. */	p->iommu.iommu_control  = p->controller_regs + SABRE_IOMMU_CONTROL;	p->iommu.iommu_tsbbase  = p->controller_regs + SABRE_IOMMU_TSBBASE;	p->iommu.iommu_flush    = p->controller_regs + SABRE_IOMMU_FLUSH;	p->iommu.write_complete_reg = p->controller_regs + SABRE_WRSYNC;	/* Sabre's IOMMU lacks ctx flushing. */	p->iommu.iommu_ctxflush = 0;                                        	/* Invalidate TLB Entries. */	control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);	control |= SABRE_IOMMUCTRL_DENAB;	sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);	for(i = 0; i < 16; i++) {		sabre_write(p->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);		sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);	}	/* Leave diag mode enabled for full-flushing done	 * in pci_iommu.c	 */	tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8));	if (!tsbbase) {		prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n");		prom_halt();	}	p->iommu.page_table = (iopte_t *)tsbbase;	p->iommu.page_table_map_base = dvma_offset;	p->iommu.dma_addr_mask = dma_mask;	memset((char *)tsbbase, 0, PAGE_SIZE << order);	sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));	control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);	control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);	control |= SABRE_IOMMUCTRL_ENAB;	switch(tsbsize) {	case 64:		control |= SABRE_IOMMU_TSBSZ_64K;		p->iommu.page_table_sz_bits = 16;		break;	case 128:		control |= SABRE_IOMMU_TSBSZ_128K;		p->iommu.page_table_sz_bits = 17;		break;	default:		prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);		prom_halt();		break;	}	sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);	/* We start with no consistent mappings. */	p->iommu.lowest_consistent_map =		1 << (p->iommu.page_table_sz_bits - PBM_LOGCLUSTERS);	for (i = 0; i < PBM_NCLUSTERS; i++) {		p->iommu.alloc_info[i].flush = 0;		p->iommu.alloc_info[i].next = 0;	}}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,						   struct pci_pbm_info *pbm){	char *name = pbm->name;	unsigned long ibase = p->controller_regs + SABRE_IOSPACE;	unsigned long mbase = p->controller_regs + SABRE_MEMSPACE;	unsigned int devfn;	unsigned long first, last, i;	u8 *addr, map;	sprintf(name, "SABRE%d PBM%c",		p->index,		(pbm == &p->pbm_A ? 'A' : 'B'));	pbm->io_space.name = pbm->mem_space.name = name;	devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1);	addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP);	map = 0;	pci_config_read8(addr, &map);	first = 8;	last = 0;	for (i = 0; i < 8; i++) {		if ((map & (1 << i)) != 0) {			if (first > i)				first = i;			if (last < i)				last = i;		}	}	pbm->io_space.start = ibase + (first << 21UL);	pbm->io_space.end   = ibase + (last << 21UL) + ((1 << 21UL) - 1);	pbm->io_space.flags = IORESOURCE_IO;	addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP);	map = 0;	pci_config_read8(addr, &map);	first = 8;	last = 0;	for (i = 0; i < 8; i++) {		if ((map & (1 << i)) != 0) {			if (first > i)				first = i;			if (last < i)				last = i;		}	}	pbm->mem_space.start = mbase + (first << 29UL);	pbm->mem_space.end   = mbase + (last << 29UL) + ((1 << 29UL) - 1);	pbm->mem_space.flags = IORESOURCE_MEM;	if (request_resource(&ioport_resource, &pbm->io_space) < 0) {		prom_printf("Cannot register PBM-%c's IO space.\n",			    (pbm == &p->pbm_A ? 'A' : 'B'));		prom_halt();	}	if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {		prom_printf("Cannot register PBM-%c's MEM space.\n",			    (pbm == &p->pbm_A ? 'A' : 'B'));		prom_halt();	}}static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node){	char namebuf[128];	u32 busrange[2];	int node;	node = prom_getchild(sabre_node);	while ((node = prom_searchsiblings(node, "pci")) != 0) {		struct pci_pbm_info *pbm;		int err;		err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));		if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))			goto next_pci;		err = prom_getproperty(node, "bus-range",				       (char *)&busrange[0], sizeof(busrange));		if (err == 0 || err == -1) {			prom_printf("APB: Error, cannot get PCI bus-range.\n");			prom_halt();		}		if (busrange[0] == 1)			pbm = &p->pbm_B;		else			pbm = &p->pbm_A;		pbm->parent = p;		pbm->prom_node = node;		pbm->pci_first_busno = busrange[0];		pbm->pci_last_busno = busrange[1];		for (err = pbm->pci_first_busno;		     err <= pbm->pci_last_busno;		     err++)			pci_bus2pbm[err] = pbm;		prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name));		err = prom_getproperty(node, "ranges",				       (char *)pbm->pbm_ranges,				       sizeof(pbm->pbm_ranges));		if (err != -1)			pbm->num_pbm_ranges =				(err / sizeof(struct linux_prom_pci_ranges));		else			pbm->num_pbm_ranges = 0;		err = prom_getproperty(node, "interrupt-map",				       (char *)pbm->pbm_intmap,				       sizeof(pbm->pbm_intmap));		if (err != -1) {			pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));			err = prom_getproperty(node, "interrupt-map-mask",					       (char *)&pbm->pbm_intmask,					       sizeof(pbm->pbm_intmask));			if (err == -1) {				prom_printf("APB: Fatal error, no interrupt-map-mask.\n");				prom_halt();			}		} else {			pbm->num_pbm_intmap = 0;			memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));		}		pbm_register_toplevel_resources(p, pbm);	next_pci:		node = prom_getsibling(node);		if (!node)			break;	}}void __init sabre_init(int pnode){	struct linux_prom64_registers pr_regs[2];	struct pci_controller_info *p;	unsigned long flags;	int tsbsize, err;	u32 busrange[2];	u32 vdma[2];	u32 upa_portid, dma_mask;	int bus;	p = kmalloc(sizeof(*p), GFP_ATOMIC);	if (!p) {		prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n");		prom_halt();	}	upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);	memset(p, 0, sizeof(*p));	spin_lock_irqsave(&pci_controller_lock, flags);	p->next = pci_controller_root;	pci_controller_root = p;	spin_unlock_irqrestore(&pci_controller_lock, flags);	p->portid = upa_portid;	p->index = pci_num_controllers++;	p->scan_bus = sabre_scan_bus;	p->irq_build = sabre_irq_build;	p->base_address_update = sabre_base_address_update;	p->resource_adjust = sabre_resource_adjust;	p->pci_ops = &sabre_ops;	/*	 * Map in SABRE register set and report the presence of this SABRE.	 */	err = prom_getproperty(pnode, "reg",			       (char *)&pr_regs[0], sizeof(pr_regs));	if(err == 0 || err == -1) {		prom_printf("SABRE: Error, cannot get U2P registers "			    "from PROM.\n");		prom_halt();	}	/*	 * First REG in property is base of entire SABRE register space.	 */	p->controller_regs = pr_regs[0].phys_addr;	pci_dma_wsync = p->controller_regs + SABRE_WRSYNC;	printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n",	       p->controller_regs, pci_dma_wsync);	/* Error interrupts are enabled later after the bus scan. */	sabre_write(p->controller_regs + SABRE_PCICTRL,		    (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));	/* Now map in PCI config space for entire SABRE. */	p->config_space = p->controller_regs + SABRE_CONFIGSPACE;	printk("SABRE: PCI config space at %016lx\n", p->config_space);	err = prom_getproperty(pnode, "virtual-dma",			       (char *)&vdma[0], sizeof(vdma));	if(err == 0 || err == -1) {		prom_printf("SABRE: Error, cannot get virtual-dma property "			    "from PROM.\n");		prom_halt();	}	dma_mask = vdma[0];	switch(vdma[1]) {		case 0x20000000:			dma_mask |= 0x1fffffff;			tsbsize = 64;			break;		case 0x40000000:			dma_mask |= 0x3fffffff;			tsbsize = 128;			break;		case 0x80000000:			dma_mask |= 0x7fffffff;			tsbsize = 128;			break;		default:			prom_printf("SABRE: strange virtual-dma size.\n");			prom_halt();	}	sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);	printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);	err = prom_getproperty(pnode, "bus-range",				       (char *)&busrange[0], sizeof(busrange));	if(err == 0 || err == -1) {		prom_printf("SABRE: Error, cannot get PCI bus-range "			    " from PROM.\n");		prom_halt();	}	p->pci_first_busno = busrange[0];	p->pci_last_busno = busrange[1];	/*	 * Handle config space reads through any Simba on APB.	 */	for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++)		pci_bus2pbm[bus] = &p->pbm_A;	/*	 * Look for APB underneath.	 */	sabre_pbm_init(p, pnode);}

⌨️ 快捷键说明

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