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

📄 pci_schizo.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	pci_setup_busmastering(pbm, pbm->pci_bus);}static void __init schizo_scan_bus(struct pci_controller_info *p){	pbm_bridge_reconfigure(p);	pbm_config_busmastering(&p->pbm_B);	p->pbm_B.is_66mhz_capable = 0;	pbm_config_busmastering(&p->pbm_A);	p->pbm_A.is_66mhz_capable = 1;	pbm_scan_bus(p, &p->pbm_B);	pbm_scan_bus(p, &p->pbm_A);	/* After the PCI bus scan is complete, we can register	 * the error interrupt handlers.	 */	schizo_register_error_handlers(p);}static void __init schizo_base_address_update(struct pci_dev *pdev, int resource){	struct pcidev_cookie *pcp = pdev->sysdata;	struct pci_pbm_info *pbm = pcp->pbm;	struct resource *res, *root;	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)		root = &pbm->io_space;	else {		root = &pbm->mem_space;		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 - root->start)) & ~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 schizo_resource_adjust(struct pci_dev *pdev,					  struct resource *res,					  struct resource *root){	res->start += root->start;	res->end += root->start;}/* Interrogate Safari match/mask registers to figure out where * PCI MEM, I/O, and Config space are for this PCI bus module. */#define SCHIZO_PCI_A_MEM_MATCH		0x00040UL#define SCHIZO_PCI_A_MEM_MASK		0x00048UL#define SCHIZO_PCI_A_IO_MATCH		0x00050UL#define SCHIZO_PCI_A_IO_MASK		0x00058UL#define SCHIZO_PCI_B_MEM_MATCH		0x00060UL#define SCHIZO_PCI_B_MEM_MASK		0x00068UL#define SCHIZO_PCI_B_IO_MATCH		0x00070UL#define SCHIZO_PCI_B_IO_MASK		0x00078UL/* VAL must be non-zero. */static unsigned long strip_to_lowest_bit_set(unsigned long val){	unsigned long tmp;	tmp = 1UL;	while (!(tmp & val))		tmp <<= 1UL;	return tmp;}static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,					  int is_pbm_a, unsigned long reg_base){	u64 mem_match, mem_mask;	u64 io_match;	u64 long a, b;	if (is_pbm_a) {		mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;		io_match = reg_base + SCHIZO_PCI_A_IO_MATCH;	} else {		mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH;		io_match = reg_base + SCHIZO_PCI_B_IO_MATCH;	}	mem_mask = mem_match + 0x8UL;	a = schizo_read(mem_match) & ~0x8000000000000000UL;	b = strip_to_lowest_bit_set(schizo_read(mem_mask));	/* It should be 2GB in size. */	pbm->mem_space.start = a;	pbm->mem_space.end = a + (b - 1UL);	pbm->mem_space.flags = IORESOURCE_MEM;	/* This 32MB area is divided into two pieces.  The first	 * 16MB is Config space, the next 16MB is I/O space.	 */	a = schizo_read(io_match) & ~0x8000000000000000UL;	pbm->config_space = a;	printk("SCHIZO PBM%c: Local PCI config space at %016lx\n",	       (is_pbm_a ? 'A' : 'B'), pbm->config_space);	a += (16UL * 1024UL * 1024UL);	pbm->io_space.start = a;	pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL);	pbm->io_space.flags = IORESOURCE_IO;}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,						   struct pci_pbm_info *pbm){	char *name = pbm->name;	sprintf(name, "SCHIZO%d PBM%c",		p->index,		(pbm == &p->pbm_A ? 'A' : 'B'));	pbm->io_space.name = pbm->mem_space.name = name;	request_resource(&ioport_resource, &pbm->io_space);	request_resource(&iomem_resource, &pbm->mem_space);	pci_register_legacy_regions(&pbm->io_space,				    &pbm->mem_space);}#define SCHIZO_STRBUF_CONTROL_A		(SCHIZO_PBM_A_REGS_OFF + 0x02800UL)#define SCHIZO_STRBUF_FLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x02808UL)#define SCHIZO_STRBUF_FSYNC_A		(SCHIZO_PBM_A_REGS_OFF + 0x02810UL)#define SCHIZO_STRBUF_CTXFLUSH_A	(SCHIZO_PBM_A_REGS_OFF + 0x02818UL)#define SCHIZO_STRBUF_CTXMATCH_A	(SCHIZO_PBM_A_REGS_OFF + 0x10000UL)#define SCHIZO_STRBUF_CONTROL_B		(SCHIZO_PBM_B_REGS_OFF + 0x02800UL)#define SCHIZO_STRBUF_FLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x02808UL)#define SCHIZO_STRBUF_FSYNC_B		(SCHIZO_PBM_B_REGS_OFF + 0x02810UL)#define SCHIZO_STRBUF_CTXFLUSH_B	(SCHIZO_PBM_B_REGS_OFF + 0x02818UL)#define SCHIZO_STRBUF_CTXMATCH_B	(SCHIZO_PBM_B_REGS_OFF + 0x10000UL)static void schizo_pbm_strbuf_init(struct pci_controller_info *p,				   struct pci_pbm_info *pbm,				   int is_pbm_a){	unsigned long base = p->controller_regs;	u64 control;	/* SCHIZO has context flushing. */	if (is_pbm_a) {		pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL_A;		pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH_A;		pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC_A;		pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH_A;		pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH_A;	} else {		pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL_B;		pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH_B;		pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC_B;		pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH_B;		pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH_B;	}	pbm->stc.strbuf_flushflag = (volatile unsigned long *)		((((unsigned long)&pbm->stc.__flushflag_buf[0])		  + 63UL)		 & ~63UL);	pbm->stc.strbuf_flushflag_pa = (unsigned long)		__pa(pbm->stc.strbuf_flushflag);	/* Turn off LRU locking and diag mode, enable the	 * streaming buffer and leave the rerun-disable	 * setting however OBP set it.	 */	control = schizo_read(pbm->stc.strbuf_control);	control &= ~(SCHIZO_STRBUF_CTRL_LPTR |		     SCHIZO_STRBUF_CTRL_LENAB |		     SCHIZO_STRBUF_CTRL_DENAB);	control |= SCHIZO_STRBUF_CTRL_ENAB;	schizo_write(pbm->stc.strbuf_control, control);	pbm->stc.strbuf_enabled = 1;}#define SCHIZO_IOMMU_CONTROL_A		(SCHIZO_PBM_A_REGS_OFF + 0x00200UL)#define SCHIZO_IOMMU_TSBBASE_A		(SCHIZO_PBM_A_REGS_OFF + 0x00208UL)#define SCHIZO_IOMMU_FLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x00210UL)#define SCHIZO_IOMMU_CTXFLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x00218UL)#define SCHIZO_IOMMU_TAG_A		(SCHIZO_PBM_A_REGS_OFF + 0x0a580UL)#define SCHIZO_IOMMU_DATA_A		(SCHIZO_PBM_A_REGS_OFF + 0x0a600UL)#define SCHIZO_IOMMU_CONTROL_B		(SCHIZO_PBM_B_REGS_OFF + 0x00200UL)#define SCHIZO_IOMMU_TSBBASE_B		(SCHIZO_PBM_B_REGS_OFF + 0x00208UL)#define SCHIZO_IOMMU_FLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x00210UL)#define SCHIZO_IOMMU_CTXFLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x00218UL)#define SCHIZO_IOMMU_TAG_B		(SCHIZO_PBM_B_REGS_OFF + 0x0a580UL)#define SCHIZO_IOMMU_DATA_B		(SCHIZO_PBM_B_REGS_OFF + 0x0a600UL)static void schizo_pbm_iommu_init(struct pci_controller_info *p,				  struct pci_pbm_info *pbm,				  int is_pbm_a){	struct pci_iommu *iommu = pbm->iommu;	unsigned long tsbbase, i, tagbase, database;	u64 control;	/* Setup initial software IOMMU state. */	spin_lock_init(&iommu->lock);	iommu->iommu_cur_ctx = 0;	/* Register addresses, SCHIZO has iommu ctx flushing. */	if (is_pbm_a) {		iommu->iommu_control  = p->controller_regs + SCHIZO_IOMMU_CONTROL_A;		iommu->iommu_tsbbase  = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A;		iommu->iommu_flush    = p->controller_regs + SCHIZO_IOMMU_FLUSH_A;		iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A;	} else {		iommu->iommu_control  = p->controller_regs + SCHIZO_IOMMU_CONTROL_B;		iommu->iommu_tsbbase  = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B;		iommu->iommu_flush    = p->controller_regs + SCHIZO_IOMMU_FLUSH_B;		iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B;	}	/* We use the main control/status register of SCHIZO as the write	 * completion register.	 */	iommu->write_complete_reg = p->controller_regs + 0x10000UL;	/*	 * Invalidate TLB Entries.	 */	control = schizo_read(iommu->iommu_control);	control |= SCHIZO_IOMMU_CTRL_DENAB;	schizo_write(iommu->iommu_control, control);	if (is_pbm_a)		tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A;	else		tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B;	for(i = 0; i < 16; i++) {		schizo_write(p->controller_regs + tagbase + (i * 8UL), 0);		schizo_write(p->controller_regs + database + (i * 8UL), 0);	}	/* Leave diag mode enabled for full-flushing done	 * in pci_iommu.c	 */	/* Using assumed page size 8K with 128K entries we need 1MB iommu page	 * table (128K ioptes * 8 bytes per iopte).  This is	 * page order 7 on UltraSparc.	 */	tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE));	if (!tsbbase) {		prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n");		prom_halt();	}	iommu->page_table = (iopte_t *)tsbbase;	iommu->page_table_sz_bits = 17;	iommu->page_table_map_base = 0xc0000000;	iommu->dma_addr_mask = 0xffffffff;	memset((char *)tsbbase, 0, IO_TSB_SIZE);	/* We start with no consistent mappings. */	iommu->lowest_consistent_map =		1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS);	for (i = 0; i < PBM_NCLUSTERS; i++) {		iommu->alloc_info[i].flush = 0;		iommu->alloc_info[i].next = 0;	}	schizo_write(iommu->iommu_tsbbase, __pa(tsbbase));	control = schizo_read(iommu->iommu_control);	control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);	control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB);	schizo_write(iommu->iommu_control, control);}static void schizo_pbm_init(struct pci_controller_info *p,			    int prom_node, int is_pbm_a){	unsigned int busrange[2];	struct pci_pbm_info *pbm;	int err;	if (is_pbm_a)		pbm = &p->pbm_A;	else		pbm = &p->pbm_B;	schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs);	pbm_register_toplevel_resources(p, pbm);	pbm->parent = p;	pbm->prom_node = prom_node;	pbm->pci_first_slot = 1;	prom_getstring(prom_node, "name",		       pbm->prom_name,		       sizeof(pbm->prom_name));	err = prom_getproperty(prom_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(prom_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(prom_node, "interrupt-map-mask",				       (char *)&pbm->pbm_intmask,				       sizeof(pbm->pbm_intmask));		if (err == -1) {			prom_printf("SCHIZO-PBM: Fatal error, no "				    "interrupt-map-mask.\n");			prom_halt();		}	} else {		pbm->num_pbm_intmap = 0;		memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));	}	err = prom_getproperty(prom_node, "bus-range",			       (char *)&busrange[0],			       sizeof(busrange));	if (err == 0 || err == -1) {		prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n");		prom_halt();	}	pbm->pci_first_busno = busrange[0];	pbm->pci_last_busno = busrange[1];	schizo_pbm_iommu_init(p, pbm, is_pbm_a);	schizo_pbm_strbuf_init(p, pbm, is_pbm_a);}static void schizo_controller_hwinit(struct pci_controller_info *p){	unsigned long pbm_a_base, pbm_b_base;	u64 tmp;	pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF;	pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF;	/* Set IRQ retry to infinity. */	schizo_write(pbm_a_base + 0x1a00UL, 0xff);	schizo_write(pbm_b_base + 0x1a00UL, 0xff);	/* Enable arbiter for all PCI slots. */	tmp = schizo_read(pbm_a_base + 0x2000UL);	tmp |= 0x3fUL;	schizo_write(pbm_a_base + 0x2000UL, tmp);	tmp = schizo_read(pbm_b_base + 0x2000UL);	tmp |= 0x3fUL;	schizo_write(pbm_b_base + 0x2000UL, tmp);}void __init schizo_init(int node, char *model_name){	struct linux_prom64_registers pr_regs[3];	struct pci_controller_info *p;	struct pci_iommu *iommu;	unsigned long flags;	u32 portid;	int is_pbm_a, err;	portid = prom_getintdefault(node, "portid", 0xff);	spin_lock_irqsave(&pci_controller_lock, flags);	for(p = pci_controller_root; p; p = p->next) {		if (p->portid == portid) {			spin_unlock_irqrestore(&pci_controller_lock, flags);			is_pbm_a = (p->pbm_A.prom_node == 0);			schizo_pbm_init(p, node, is_pbm_a);			return;		}	}	spin_unlock_irqrestore(&pci_controller_lock, flags);	p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);	if (!p) {		prom_printf("SCHIZO: Fatal memory allocation error.\n");		prom_halt();	}	memset(p, 0, sizeof(*p));	iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);	if (!iommu) {		prom_printf("SCHIZO: Fatal memory allocation error.\n");		prom_halt();	}	memset(iommu, 0, sizeof(*iommu));	p->pbm_A.iommu = iommu;	iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);	if (!iommu) {		prom_printf("SCHIZO: Fatal memory allocation error.\n");		prom_halt();	}	memset(iommu, 0, sizeof(*iommu));	p->pbm_B.iommu = iommu;	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 = portid;	p->index = pci_num_controllers++;	p->pbms_same_domain = 0;	p->scan_bus = schizo_scan_bus;	p->irq_build = schizo_irq_build;	p->base_address_update = schizo_base_address_update;	p->resource_adjust = schizo_resource_adjust;	p->pci_ops = &schizo_ops;	/* Three OBP regs:	 * 1) PBM controller regs	 * 2) Schizo front-end controller regs (same for both PBMs)	 * 3) PBM PCI config space	 */	err = prom_getproperty(node, "reg",			       (char *)&pr_regs[0],			       sizeof(pr_regs));	if (err == 0 || err == -1) {		prom_printf("SCHIZO: Fatal error, no reg property.\n");		prom_halt();	}	p->controller_regs = pr_regs[1].phys_addr - 0x10000UL;	printk("PCI: Found SCHIZO, control regs at %016lx\n",	       p->controller_regs);	/* Like PSYCHO we have a 2GB aligned area for memory space. */	pci_memspace_mask = 0x7fffffffUL;	/* Init core controller. */	schizo_controller_hwinit(p);	is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);	schizo_pbm_init(p, node, is_pbm_a);}

⌨️ 快捷键说明

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