summaryrefslogtreecommitdiff
path: root/os/boot/pc/pci.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2008-06-11 14:21:44 +0000
committerCharles.Forsyth <devnull@localhost>2008-06-11 14:21:44 +0000
commit8a8c2d742b51525f66c2210e3c8a251de10022ff (patch)
tree8282ce595e5fbe2e487dc20f54891d9e9e7cbf37 /os/boot/pc/pci.c
parent31a18a6996a6b5927e39cc553696c167e6c88e3d (diff)
20080611-1520
Diffstat (limited to 'os/boot/pc/pci.c')
-rw-r--r--os/boot/pc/pci.c300
1 files changed, 225 insertions, 75 deletions
diff --git a/os/boot/pc/pci.c b/os/boot/pc/pci.c
index c7b9eda5..a83a10fa 100644
--- a/os/boot/pc/pci.c
+++ b/os/boot/pc/pci.c
@@ -23,6 +23,16 @@ enum { /* configuration mechanism #1 */
MaxUBN = 255,
};
+enum
+{ /* command register */
+ IOen = (1<<0),
+ MEMen = (1<<1),
+ MASen = (1<<2),
+ MemWrInv = (1<<4),
+ PErrEn = (1<<6),
+ SErrEn = (1<<8),
+};
+
static Lock pcicfglock;
static Lock pcicfginitlock;
static int pcicfgmode = -1;
@@ -145,7 +155,8 @@ pciscan(int bno, Pcidev** list)
*list = head;
for(p = head; p != nil; p = p->link){
/*
- * Find PCI-PCI and PCI-Cardbus bridges and recursively descend the tree.
+ * Find PCI-PCI and PCI-Cardbus bridges
+ * and recursively descend the tree.
*/
if(p->ccrb != 0x06 || p->ccru != 0x04)
continue;
@@ -181,7 +192,16 @@ pciscan(int bno, Pcidev** list)
pcicfgw32(p, PciPBN, l);
}
else{
- maxubn = ubn;
+ /*
+ * You can't go back.
+ * This shouldn't be possible, but the
+ * Iwill DK8-HTX seems to have subordinate
+ * bus numbers which get smaller on the
+ * way down. Need to look more closely at
+ * this.
+ */
+ if(ubn > maxubn)
+ maxubn = ubn;
pciscan(sbn, &p->bridge);
}
}
@@ -189,7 +209,18 @@ pciscan(int bno, Pcidev** list)
return maxubn;
}
-static uchar
+static uchar
+null_link(Pcidev *, uchar )
+{
+ return 0;
+}
+
+static void
+null_init(Pcidev *, uchar , uchar )
+{
+}
+
+static uchar
pIIx_link(Pcidev *router, uchar link)
{
uchar pirq;
@@ -199,13 +230,13 @@ pIIx_link(Pcidev *router, uchar link)
return (pirq < 16)? pirq: 0;
}
-static void
+static void
pIIx_init(Pcidev *router, uchar link, uchar irq)
{
pcicfgw8(router, link, irq);
}
-static uchar
+static uchar
via_link(Pcidev *router, uchar link)
{
uchar pirq;
@@ -216,7 +247,7 @@ via_link(Pcidev *router, uchar link)
return (link & 1)? (pirq >> 4): (pirq & 15);
}
-static void
+static void
via_init(Pcidev *router, uchar link, uchar irq)
{
uchar pirq;
@@ -227,7 +258,7 @@ via_init(Pcidev *router, uchar link, uchar irq)
pcicfgw8(router, 0x55 + (link>>1), pirq);
}
-static uchar
+static uchar
opti_link(Pcidev *router, uchar link)
{
uchar pirq = 0;
@@ -238,7 +269,7 @@ opti_link(Pcidev *router, uchar link)
return (link & 0x10)? (pirq >> 4): (pirq & 15);
}
-static void
+static void
opti_init(Pcidev *router, uchar link, uchar irq)
{
uchar pirq;
@@ -249,7 +280,7 @@ opti_init(Pcidev *router, uchar link, uchar irq)
pcicfgw8(router, 0xb8 + (link >> 5), pirq);
}
-static uchar
+static uchar
ali_link(Pcidev *router, uchar link)
{
/* No, you're not dreaming */
@@ -261,7 +292,7 @@ ali_link(Pcidev *router, uchar link)
return (link & 1)? map[pirq&15]: map[pirq>>4];
}
-static void
+static void
ali_init(Pcidev *router, uchar link, uchar irq)
{
/* Inverse of map in ali_link */
@@ -274,7 +305,7 @@ ali_init(Pcidev *router, uchar link, uchar irq)
pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
}
-static uchar
+static uchar
cyrix_link(Pcidev *router, uchar link)
{
uchar pirq;
@@ -284,7 +315,7 @@ cyrix_link(Pcidev *router, uchar link)
return ((link & 1)? pirq >> 4: pirq & 15);
}
-static void
+static void
cyrix_init(Pcidev *router, uchar link, uchar irq)
{
uchar pirq;
@@ -295,64 +326,46 @@ cyrix_init(Pcidev *router, uchar link, uchar irq)
pcicfgw8(router, 0x5c + (link>>1), pirq);
}
-enum {
- Intel = 0x8086,
- Intel_82371FB_0 = 0x122e,
- Intel_82371MX_0 = 0x1234,
- 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,
- Intel_82801CAM_0 = 0x248c,
- Intel_82801DBM_0 = 0x24cc,
- Intel_82801EB_0 = 0x24d0,
- Intel_82801FB_0 = 0x2640,
- 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);
+ void (*sb_initialize)(Pcidev *, uchar, uchar);
} bridge_t;
static bridge_t southbridges[] = {
-{ Intel, Intel_82371FB_0, pIIx_link, pIIx_init },
-{ Intel, Intel_82371MX_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 },
-{ Intel, Intel_82801CAM_0, pIIx_link, pIIx_init },
-{ Intel, Intel_82801DBM_0, pIIx_link, pIIx_init },
-{ Intel, Intel_82801EB_0, pIIx_link, pIIx_init },
-{ Intel, Intel_82801FB_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 }
+ { 0x8086, 0x122e, pIIx_link, pIIx_init }, // Intel 82371FB
+ { 0x8086, 0x1234, pIIx_link, pIIx_init }, // Intel 82371MX
+ { 0x8086, 0x7000, pIIx_link, pIIx_init }, // Intel 82371SB
+ { 0x8086, 0x7110, pIIx_link, pIIx_init }, // Intel 82371AB
+ { 0x8086, 0x7198, pIIx_link, pIIx_init }, // Intel 82443MX (fn 1)
+ { 0x8086, 0x2410, pIIx_link, pIIx_init }, // Intel 82801AA
+ { 0x8086, 0x2420, pIIx_link, pIIx_init }, // Intel 82801AB
+ { 0x8086, 0x2440, pIIx_link, pIIx_init }, // Intel 82801BA
+ { 0x8086, 0x244c, pIIx_link, pIIx_init }, // Intel 82801BAM
+ { 0x8086, 0x2480, pIIx_link, pIIx_init }, // Intel 82801CA
+ { 0x8086, 0x248c, pIIx_link, pIIx_init }, // Intel 82801CAM
+ { 0x8086, 0x24c0, pIIx_link, pIIx_init }, // Intel 82801DBL
+ { 0x8086, 0x24cc, pIIx_link, pIIx_init }, // Intel 82801DBM
+ { 0x8086, 0x24d0, pIIx_link, pIIx_init }, // Intel 82801EB
+ { 0x8086, 0x2640, pIIx_link, pIIx_init }, // Intel 82801FB
+ { 0x8086, 0x27b8, pIIx_link, pIIx_init }, // Intel 82801GB
+ { 0x8086, 0x27b9, pIIx_link, pIIx_init }, // Intel 82801GBM
+ { 0x1106, 0x0586, via_link, via_init }, // Viatech 82C586
+ { 0x1106, 0x0596, via_link, via_init }, // Viatech 82C596
+ { 0x1106, 0x0686, via_link, via_init }, // Viatech 82C686
+ { 0x1106, 0x3227, via_link, via_init }, // Viatech VT8237
+ { 0x1045, 0xc700, opti_link, opti_init }, // Opti 82C700
+ { 0x10b9, 0x1533, ali_link, ali_init }, // Al M1533
+ { 0x1039, 0x0008, pIIx_link, pIIx_init }, // SI 503
+ { 0x1039, 0x0496, pIIx_link, pIIx_init }, // SI 496
+ { 0x1078, 0x0100, cyrix_link, cyrix_init }, // Cyrix 5530 Legacy
+
+ { 0x1002, 0x4377, nil, nil }, // ATI Radeon Xpress 200M
+ { 0x1002, 0x4372, nil, nil }, // ATI SB400
+ { 0x1022, 0x746B, nil, nil }, // AMD 8111
+ { 0x10DE, 0x00D1, nil, nil }, // NVIDIA nForce 3
+ { 0x10DE, 0x00E0, nil, nil }, // NVIDIA nForce 3 250 Series
+ { 0x1166, 0x0200, nil, nil }, // ServerWorks ServerSet III LE
};
typedef struct {
@@ -423,7 +436,7 @@ pcirouting(void)
vid, did);
return;
}
-
+
pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0];
size = (r->rt_size[1] << 8)|r->rt_size[0];
@@ -443,12 +456,12 @@ pcirouting(void)
// 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)
+ if (vdid == 0xFFFFFFFF || vdid == 0)
continue;
vid = vdid;
did = vdid >> 16;
-
+
pci = nil;
while ((pci = pcimatch(pci, vid, did)) != nil) {
@@ -456,13 +469,13 @@ pcirouting(void)
continue;
pin = pcicfgr8(pci, PciINTP);
- if (pin == 0 || pin == 0xff)
+ 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",
+ print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n",
vid, did, pin, irq);
pcicfgw8(pci, PciINTL, irq);
pci->intl = irq;
@@ -521,7 +534,7 @@ pcicfginit(void)
}
outb(PciCSE, n);
}
-
+
if(pcicfgmode < 0)
goto out;
@@ -841,12 +854,149 @@ pcireset(void)
}
void
+pcisetioe(Pcidev* p)
+{
+ p->pcr |= IOen;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrioe(Pcidev* p)
+{
+ p->pcr &= ~IOen;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
pcisetbme(Pcidev* p)
{
- int pcr;
+ p->pcr |= MASen;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrbme(Pcidev* p)
+{
+ p->pcr &= ~MASen;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pcisetmwi(Pcidev* p)
+{
+ p->pcr |= MemWrInv;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+void
+pciclrmwi(Pcidev* p)
+{
+ p->pcr &= ~MemWrInv;
+ pcicfgw16(p, PciPCR, p->pcr);
+}
+
+static int
+pcigetpmrb(Pcidev* p)
+{
+ int ptr;
+
+ if(p->pmrb != 0)
+ return p->pmrb;
+ p->pmrb = -1;
+
+ /*
+ * If there are no extended capabilities implemented,
+ * (bit 4 in the status register) assume there's no standard
+ * power management method.
+ * Find the capabilities pointer based on PCI header type.
+ */
+ if(!(pcicfgr16(p, PciPSR) & 0x0010))
+ return -1;
+ switch(pcicfgr8(p, PciHDT)){
+ default:
+ return -1;
+ case 0: /* all other */
+ case 1: /* PCI to PCI bridge */
+ ptr = 0x34;
+ break;
+ case 2: /* CardBus bridge */
+ ptr = 0x14;
+ break;
+ }
+ ptr = pcicfgr32(p, ptr);
+
+ while(ptr != 0){
+ /*
+ * Check for validity.
+ * Can't be in standard header and must be double
+ * word aligned.
+ */
+ if(ptr < 0x40 || (ptr & ~0xFC))
+ return -1;
+ if(pcicfgr8(p, ptr) == 0x01){
+ p->pmrb = ptr;
+ return ptr;
+ }
+
+ ptr = pcicfgr8(p, ptr+1);
+ }
+
+ return -1;
+}
- pcr = pcicfgr16(p, PciPCR);
- pcr |= 0x0004;
- pcicfgw16(p, PciPCR, pcr);
+int
+pcigetpms(Pcidev* p)
+{
+ int pmcsr, ptr;
+
+ if((ptr = pcigetpmrb(p)) == -1)
+ return -1;
+
+ /*
+ * Power Management Register Block:
+ * offset 0: Capability ID
+ * 1: next item pointer
+ * 2: capabilities
+ * 4: control/status
+ * 6: bridge support extensions
+ * 7: data
+ */
+ pmcsr = pcicfgr16(p, ptr+4);
+
+ return pmcsr & 0x0003;
}
+int
+pcisetpms(Pcidev* p, int state)
+{
+ int ostate, pmc, pmcsr, ptr;
+
+ if((ptr = pcigetpmrb(p)) == -1)
+ return -1;
+
+ pmc = pcicfgr16(p, ptr+2);
+ pmcsr = pcicfgr16(p, ptr+4);
+ ostate = pmcsr & 0x0003;
+ pmcsr &= ~0x0003;
+
+ switch(state){
+ default:
+ return -1;
+ case 0:
+ break;
+ case 1:
+ if(!(pmc & 0x0200))
+ return -1;
+ break;
+ case 2:
+ if(!(pmc & 0x0400))
+ return -1;
+ break;
+ case 3:
+ break;
+ }
+ pmcsr |= state;
+ pcicfgw16(p, ptr+4, pmcsr);
+
+ return ostate;
+}