plan 9 kernel history: overview | file list | diff list

2001/1003/pc/pci.c (diff list | history)

2001/0928/sys/src/9/pc/pci.c:507,5132001/1003/sys/src/9/pc/pci.c:507,786 (short | long | prev | next)
2001/0622    
	return ubn; 
} 
 
2001/1003    
static uchar  
pIIx_link(Pcidev *router, uchar link) 
{ 
	uchar pirq; 
 
	/* link should be 0x60, 0x61, 0x62, 0x63 */ 
	pirq = pcicfgr8(router, link); 
	return (pirq < 16)? pirq: 0; 
} 
 
static void  
pIIx_init(Pcidev *router, uchar link, uchar irq) 
{ 
	pcicfgw8(router, link, irq); 
} 
 
static uchar  
via_link(Pcidev *router, uchar link) 
{ 
	uchar pirq; 
 
	/* link should be 1, 2, 3, 5 */ 
	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0; 
 
	return (link & 1)? (pirq >> 4): (pirq & 15); 
} 
 
static void  
via_init(Pcidev *router, uchar link, uchar irq) 
{ 
	uchar pirq; 
 
	pirq = pcicfgr8(router, 0x55 + (link >> 1)); 
	pirq &= (link & 1)? 0x0f: 0xf0; 
	pirq |= (link & 1)? (irq << 4): (irq & 15); 
	pcicfgw8(router, 0x55 + (link>>1), pirq); 
} 
 
static uchar  
opti_link(Pcidev *router, uchar link) 
{ 
	uchar pirq = 0; 
 
	/* link should be 0x02, 0x12, 0x22, 0x32 */ 
	if ((link & 0xcf) == 0x02) 
		pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 
	return (link & 0x10)? (pirq >> 4): (pirq & 15); 
} 
 
static void  
opti_init(Pcidev *router, uchar link, uchar irq) 
{ 
	uchar pirq; 
 
	pirq = pcicfgr8(router, 0xb8 + (link >> 5)); 
    	pirq &= (link & 0x10)? 0x0f : 0xf0; 
    	pirq |= (link & 0x10)? (irq << 4): (irq & 15); 
	pcicfgw8(router, 0xb8 + (link >> 5), pirq); 
} 
 
static uchar  
ali_link(Pcidev *router, uchar link) 
{ 
	/* No, you're not dreaming */ 
	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; 
	uchar pirq; 
 
	/* link should be 0x01..0x08 */ 
	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 
	return (link & 1)? map[pirq&15]: map[pirq>>4]; 
} 
 
static void  
ali_init(Pcidev *router, uchar link, uchar irq) 
{ 
	/* Inverse of map in ali_link */ 
	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; 
	uchar pirq; 
 
	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); 
	pirq &= (link & 1)? 0x0f: 0xf0; 
	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15); 
	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq); 
} 
 
static uchar  
cyrix_link(Pcidev *router, uchar link) 
{ 
	uchar pirq; 
 
	/* link should be 1, 2, 3, 4 */ 
	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1)); 
	return ((link & 1)? pirq >> 4: pirq & 15); 
} 
 
static void  
cyrix_init(Pcidev *router, uchar link, uchar irq) 
{ 
	uchar pirq; 
 
	pirq = pcicfgr8(router, 0x5c + (link>>1)); 
	pirq &= (link & 1)? 0x0f: 0xf0; 
	pirq |= (link & 1)? (irq << 4): (irq & 15); 
	pcicfgw8(router, 0x5c + (link>>1), pirq); 
} 
 
enum { 
	Intel = 0x8086,		 
		Intel_82371FB_0 = 0x122e, 
		Intel_82371SB_0 = 0x7000, 
		Intel_82371AB_0 = 0x7110, 
		Intel_82443MX_1 = 0x7198, 
		Intel_82801AA_0 = 0x2410, 
		Intel_82801AB_0 = 0x2420, 
		Intel_82801BA_0 = 0x2440, 
		Intel_82801BAM_0 = 0x244c, 
	Viatech = 0x1106, 
		Via_82C586_0 = 0x0586, 
		Via_82C596 = 0x0596, 
		Via_82C686 = 0x0686, 
	Opti = 0x1045, 
		Opti_82C700 = 0xc700, 
	Al = 0x10b9, 
		Al_M1533 = 0x1533, 
	SI = 0x1039, 
		SI_503 = 0x0008, 
		SI_496 = 0x0496, 
	Cyrix = 0x1078, 
		Cyrix_5530_Legacy = 0x0100, 
}; 
 
typedef struct { 
	ushort	sb_vid, sb_did; 
	uchar	(*sb_translate)(Pcidev *, uchar); 
	void		(*sb_initialize)(Pcidev *, uchar, uchar);	 
} bridge_t; 
 
static bridge_t southbridges[] = { 
{	Intel, Intel_82371FB_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82371SB_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82371AB_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82443MX_1,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82801AA_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82801AB_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82801BA_0,		pIIx_link,		pIIx_init }, 
{	Intel, Intel_82801BAM_0,		pIIx_link,		pIIx_init }, 
{	Viatech, Via_82C586_0,		via_link,		via_init }, 
{	Viatech, Via_82C596,		via_link,		via_init }, 
{	Viatech, Via_82C686,		via_link,		via_init }, 
{	Opti, Opti_82C700,			opti_link,		opti_init }, 
{	Al, Al_M1533,				ali_link,		ali_init }, 
{	SI, SI_503,				pIIx_link,		pIIx_init }, 
{	SI, SI_496,				pIIx_link,		pIIx_init }, 
{	Cyrix, Cyrix_5530_Legacy,	cyrix_link,	cyrix_init } 
}; 
 
typedef struct { 
	uchar	e_bus;			// Pci bus number 
	uchar	e_dev;			// Pci device number 
	uchar	e_maps[12];		// Avoid structs!  Link and mask. 
	uchar	e_slot;			// Add-in/built-in slot 
	uchar	e_reserved; 
} slot_t; 
 
typedef struct { 
	uchar	rt_signature[4];	// Routing table signature 
	uchar	rt_version[2];		// Version number 
	uchar	rt_size[2];			// Total table size 
	uchar	rt_bus;			// Interrupt router bus number 
	uchar	rt_devfn;			// Router's devfunc 
	uchar	rt_pciirqs[2];		// Exclusive PCI irqs 
	uchar	rt_compat[4];		// Compatible PCI interrupt router 
	uchar	rt_miniport[4];		// Miniport data 
	uchar	rt_reserved[11]; 
	uchar	rt_checksum; 
} router_t; 
 
static ushort pciirqs;			// Exclusive PCI irqs 
static bridge_t *southbridge;	// Which southbridge to use. 
 
1997/0327    
static void 
2001/1003    
pcirouting(void) 
{ 
	uchar *p, pin, irq; 
	ulong tbdf, vdid; 
	ushort vid, did; 
	router_t *r; 
	slot_t *e; 
	int size, i, fn; 
	Pcidev *sbpci, *pci; 
 
	// Peek in the BIOS 
	for (p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) 
		if (p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') 
			break; 
 
	if (p >= (uchar *)KADDR(0xfffff)) 
		return; 
 
	r = (router_t *)p; 
 
	// print("PCI interrupt routing table version %d.%d at %.6uX\n", 
	// 	r->rt_version[0], r->rt_version[1], (ulong)r & 0xfffff); 
 
	tbdf = (BusPCI << 24)|(r->rt_bus << 16)|(r->rt_devfn << 8); 
	vdid = pcicfgrw32(tbdf, PciVID, 0, 1); 
	vid = vdid; 
	did = vdid >> 16; 
 
	for (i = 0; i != nelem(southbridges); i++) 
		if (vid == southbridges[i].sb_vid && did == southbridges[i].sb_did) 
			break; 
 
	if (i == nelem(southbridges)) { 
		print("pcirouting: South bridge %.4uX, %.4uX not found\n", vid, did); 
		return; 
	} 
	southbridge = &southbridges[i]; 
 
	if ((sbpci = pcimatch(nil, vid, did)) == nil) { 
		print("pcirouting: Cannot match south bridge %.4uX, %.4uX\n", 
			  vid, did); 
		return; 
	} 
	 
	pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0]; 
 
	size = (r->rt_size[1] << 8)|r->rt_size[0]; 
	for (e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) { 
		// print("%.2uX/%.2uX %.2uX: ", e->e_bus, e->e_dev, e->e_slot); 
		// for (i = 0; i != 4; i++) { 
		// 	uchar *m = &e->e_maps[i * 3]; 
		// 	print("[%d] %.2uX %.4uX ", 
		// 		i, m[0], (m[2] << 8)|m[1]); 
		// } 
		// print("\n"); 
 
		for (fn = 0; fn != 8; fn++) { 
			uchar *m; 
 
			// Retrieve the did and vid through the devfn before 
			// obtaining the Pcidev structure. 
			tbdf = (BusPCI << 24)|(e->e_bus << 16)|((e->e_dev | fn) << 8); 
			vdid = pcicfgrw32(tbdf, PciVID, 0, 1); 
			if (vdid == 0xFFFFFFFF || vdid == 0)  
				continue; 
 
			vid = vdid; 
			did = vdid >> 16; 
	 
			pci = nil; 
			while ((pci = pcimatch(pci, vid, did)) != nil) { 
 
				if (pci->intl != 0 && pci->intl != 0xFF) 
					continue; 
 
				pin = pcicfgr8(pci, PciINTP); 
				if (pin == 0 || pin == 0xff)  
					continue; 
	 
				m = &e->e_maps[(pin - 1) * 3]; 
				irq = southbridge->sb_translate(sbpci, m[0]); 
				if (irq) { 
					print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n",  
						  vid, did, pin, irq); 
					pcicfgw8(pci, PciINTL, irq); 
					pci->intl = irq; 
				} 
			} 
		} 
	} 
} 
 
static void 
1997/0327    
pcicfginit(void) 
1995/0517    
{ 
1998/0312    
	char *p; 
2001/0928/sys/src/9/pc/pci.c:610,6152001/1003/sys/src/9/pc/pci.c:883,891
2001/0622    
		qunlock(&pcicfginitlock); 
1999/0301    
		return; 
1997/0327    
	} 
2001/1003    
 
	pcirouting(); 
 
1999/0301    
out: 
2001/0622    
	qunlock(&pcicfginitlock); 
1997/0327    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)