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

📄 pci_psycho.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	 * all PCI-to-PCI bridges under each PBM.  The generic bus	 * probing will fix them up.	 */	pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);	pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno);	/* Move PBM A out of the way. */	pbm = &p->pbm_A;	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,					0, PBM_BRIDGE_BUS);	pci_config_write8(addr, 0xff);	addr = psycho_pci_config_mkaddr(pbm, 0xff,					0, PBM_BRIDGE_SUBORDINATE);	pci_config_write8(addr, 0xff);	/* Now we can safely renumber both PBMs. */	pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);	pbm_renumber(&p->pbm_A, 0xff);}static void __init pbm_config_busmastering(struct pci_pbm_info *pbm){	u8 *addr;	/* Set cache-line size to 64 bytes, this is actually	 * a nop but I do it for completeness.	 */	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,					0, PCI_CACHE_LINE_SIZE);	pci_config_write8(addr, 64 / sizeof(u32));	/* Set PBM latency timer to 64 PCI clocks. */	addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,					0, PCI_LATENCY_TIMER);	pci_config_write8(addr, 64);}static void __init pbm_scan_bus(struct pci_controller_info *p,				struct pci_pbm_info *pbm){	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,				    p->pci_ops,				    pbm);	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);	pci_record_assignments(pbm, pbm->pci_bus);	pci_assign_unassigned(pbm, pbm->pci_bus);	pci_fixup_irq(pbm, pbm->pci_bus);	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);	pci_setup_busmastering(pbm, pbm->pci_bus);}static void __init psycho_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.	 */	psycho_register_error_handlers(p);}static void __init psycho_iommu_init(struct pci_controller_info *p){	unsigned long tsbbase, i;	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 + PSYCHO_IOMMU_CONTROL;	p->iommu.iommu_tsbbase  = p->controller_regs + PSYCHO_IOMMU_TSBBASE;	p->iommu.iommu_flush    = p->controller_regs + PSYCHO_IOMMU_FLUSH;	/* PSYCHO's IOMMU lacks ctx flushing. */	p->iommu.iommu_ctxflush = 0;	/* We use the main control register of PSYCHO as the write	 * completion register.	 */	p->iommu.write_complete_reg = p->controller_regs + PSYCHO_CONTROL;	/*	 * Invalidate TLB Entries.	 */	control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);	control |= PSYCHO_IOMMU_CTRL_DENAB;	psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);	for(i = 0; i < 16; i++) {		psycho_write(p->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);		psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (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, 7);	if (!tsbbase) {		prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n");		prom_halt();	}	p->iommu.page_table = (iopte_t *)tsbbase;	p->iommu.page_table_sz_bits = 17;	p->iommu.page_table_map_base = 0xc0000000;	p->iommu.dma_addr_mask = 0xffffffff;	memset((char *)tsbbase, 0, PAGE_SIZE << 7);	/* 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;	}	psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));	control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);	control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);	control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);	psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);	/* If necessary, hook us up for starfire IRQ translations. */	if(this_is_starfire)		p->starfire_cookie = starfire_hookup(p->portid);	else		p->starfire_cookie = NULL;}#define PSYCHO_IRQ_RETRY	0x1a00UL#define PSYCHO_PCIA_DIAG	0x2020UL#define PSYCHO_PCIB_DIAG	0x4020UL#define  PSYCHO_PCIDIAG_RESV	 0xffffffffffffff80 /* Reserved                     */#define  PSYCHO_PCIDIAG_DRETRY	 0x0000000000000040 /* Disable retry limit          */#define  PSYCHO_PCIDIAG_DISYNC	 0x0000000000000020 /* Disable DMA wr / irq sync    */#define  PSYCHO_PCIDIAG_DDWSYNC	 0x0000000000000010 /* Disable DMA wr / PIO rd sync */#define  PSYCHO_PCIDIAG_IDDPAR	 0x0000000000000008 /* Invert DMA data parity       */#define  PSYCHO_PCIDIAG_IPDPAR	 0x0000000000000004 /* Invert PIO data parity       */#define  PSYCHO_PCIDIAG_IPAPAR	 0x0000000000000002 /* Invert PIO address parity    */#define  PSYCHO_PCIDIAG_LPBACK	 0x0000000000000001 /* Enable loopback mode         */static void psycho_controller_hwinit(struct pci_controller_info *p){	u64 tmp;	/* PROM sets the IRQ retry value too low, increase it. */	psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff);	/* Enable arbiter for all PCI slots. */	tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL);	tmp |= PSYCHO_PCICTRL_AEN;	psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp);	tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL);	tmp |= PSYCHO_PCICTRL_AEN;	psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp);	/* Disable DMA write / PIO read synchronization on	 * both PCI bus segments.	 * [ U2P Erratum 1243770, STP2223BGA data sheet ]	 */	tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG);	tmp |= PSYCHO_PCIDIAG_DDWSYNC;	psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp);	tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG);	tmp |= PSYCHO_PCIDIAG_DDWSYNC;	psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp);}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,						   struct pci_pbm_info *pbm){	char *name = pbm->name;	sprintf(name, "PSYCHO%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);}static void psycho_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;	if (is_pbm_a) {		pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_A;		pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_A;		pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_A;	} else {		pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_B;		pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_B;		pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_B;	}	/* PSYCHO's streaming buffer lacks ctx flushing. */	pbm->stc.strbuf_ctxflush      = 0;	pbm->stc.strbuf_ctxmatch_base = 0;	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);	/* Enable the streaming buffer.  We have to be careful	 * just in case OBP left it with LRU locking enabled.	 *	 * It is possible to control if PBM will be rerun on	 * line misses.  Currently I just retain whatever setting	 * OBP left us with.  All checks so far show it having	 * a value of zero.	 */#undef PSYCHO_STRBUF_RERUN_ENABLE#undef PSYCHO_STRBUF_RERUN_DISABLE	control = psycho_read(pbm->stc.strbuf_control);	control |= PSYCHO_STRBUF_CTRL_ENAB;	control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);#ifdef PSYCHO_STRBUF_RERUN_ENABLE	control &= ~(PSYCHO_STRBUF_CTRL_RRDIS);#else#ifdef PSYCHO_STRBUF_RERUN_DISABLE	control |= PSYCHO_STRBUF_CTRL_RRDIS;#endif#endif	psycho_write(pbm->stc.strbuf_control, control);	pbm->stc.strbuf_enabled = 1;}#define PSYCHO_IOSPACE_A	0x002000000UL#define PSYCHO_IOSPACE_B	0x002010000UL#define PSYCHO_IOSPACE_SIZE	0x00000ffffUL#define PSYCHO_MEMSPACE_A	0x100000000UL#define PSYCHO_MEMSPACE_B	0x180000000UL#define PSYCHO_MEMSPACE_SIZE	0x07fffffffULstatic void psycho_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;		pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A;		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A;	} else {		pbm = &p->pbm_B;		pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B;		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B;	}	pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;	pbm->io_space.flags = IORESOURCE_IO;	pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE;	pbm->mem_space.flags = IORESOURCE_MEM;	pbm_register_toplevel_resources(p, pbm);	pbm->parent = p;	pbm->prom_node = prom_node;	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("PSYCHO-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("PSYCHO-PBM: Fatal error, no bus-range.\n");		prom_halt();	}	pbm->pci_first_busno = busrange[0];	pbm->pci_last_busno = busrange[1];	psycho_pbm_strbuf_init(p, pbm, is_pbm_a);}#define PSYCHO_CONFIGSPACE	0x001000000ULvoid __init psycho_init(int node){	struct linux_prom64_registers pr_regs[3];	struct pci_controller_info *p;	unsigned long flags;	u32 upa_portid;	int is_pbm_a, err;	upa_portid = prom_getintdefault(node, "upa-portid", 0xff);	spin_lock_irqsave(&pci_controller_lock, flags);	for(p = pci_controller_root; p; p = p->next) {		if (p->portid == upa_portid) {			spin_unlock_irqrestore(&pci_controller_lock, flags);			is_pbm_a = (p->pbm_A.prom_node == 0);			psycho_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("PSYCHO: Fatal memory allocation error.\n");		prom_halt();	}	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 = psycho_scan_bus;	p->irq_build = psycho_irq_build;	p->base_address_update = psycho_base_address_update;	p->resource_adjust = psycho_resource_adjust;	p->pci_ops = &psycho_ops;	err = prom_getproperty(node, "reg",			       (char *)&pr_regs[0],			       sizeof(pr_regs));	if (err == 0 || err == -1) {		prom_printf("PSYCHO: Fatal error, no reg property.\n");		prom_halt();	}	p->controller_regs = pr_regs[2].phys_addr;	printk("PCI: Found PSYCHO, control regs at %016lx\n",	       p->controller_regs);	p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE;	printk("PSYCHO: PCI config space at %016lx\n", p->config_space);	/*	 * Psycho's PCI MEM space is mapped to a 2GB aligned area, so	 * we need to adjust our MEM space mask.	 */	pci_memspace_mask = 0x7fffffffUL;	psycho_controller_hwinit(p);	psycho_iommu_init(p);	is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);	psycho_pbm_init(p, node, is_pbm_a);}

⌨️ 快捷键说明

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