@@ 45,31 45,22 @@ static variant_t variant[] = {
/* Cardbus registers */
enum {
SocketEvent = 0,
+ SE_CCD = 3 << 1,
+ SE_POWER = 1 << 3,
SocketMask = 1,
SocketState = 2,
+ SS_CCD = 3 << 1,
+ SS_POWER = 1 << 3,
+ SS_PC16 = 1 << 4,
+ SS_CBC = 1 << 5,
+ SS_NOTCARD = 1 << 7,
+ SS_BADVCC = 1 << 9,
+ SS_5V = 1 << 10,
+ SS_3V = 1 << 11,
SocketForce = 3,
SocketControl = 4,
-};
-
-enum {
- SS_CCD = 3 << 1,
- SS_POWER = 1 << 3,
- SS_PC16 = 1 << 4,
- SS_CBC = 1 << 5,
- SS_NOTCARD = 1 << 7,
- SS_BADVCC = 1 << 9,
- SS_5V = 1 << 10,
- SS_3V = 1 << 11,
-};
-
-enum {
- SC_5V = 0x22,
- SC_3V = 0x33,
-};
-
-enum {
- SE_CCD = SS_CCD,
- SE_POWER = SS_POWER,
+ SC_5V = 0x22,
+ SC_3V = 0x33,
};
enum {
@@ 523,9 514,14 @@ devpccardlink(void)
cb->cb_pci = pci;
cb->cb_variant = &variant[i];
- if (intl != -1 && intl != pci->intl)
- intrenable(pci->intl, interrupt, cb, pci->tbdf, "cardbus");
- intl = pci->intl;
+ pcicfgw32(pci, PciCBMBR0, 0xffffffff);
+ pcicfgw32(pci, PciCBMLR0, 0);
+ pcicfgw32(pci, PciCBMBR1, 0xffffffff);
+ pcicfgw32(pci, PciCBMLR1, 0);
+ pcicfgw32(pci, PciCBIBR0, 0xffffffff);
+ pcicfgw32(pci, PciCBILR0, 0);
+ pcicfgw32(pci, PciCBIBR1, 0xffffffff);
+ pcicfgw32(pci, PciCBILR1, 0);
// Set up PCI bus numbers if needed.
if (pcicfgr8(pci, PciSBN) == 0) {
@@ 545,7 541,10 @@ devpccardlink(void)
if (pci->intl == 0xff || pci->intl == 0)
print("#Y%d: No interrupt?\n", (int)(cb - cbslots));
}
-
+ if (intl != -1 && intl != pci->intl)
+ intrenable(pci->intl, interrupt, cb, pci->tbdf, "cardbus");
+ intl = pci->intl;
+
if ((baddr = pcicfgr32(cb->cb_pci, PciBAR0)) == 0) {
int align = (pci->did == Ricoh_478_did)? 0x10000: 0x1000;
@@ 696,6 695,9 @@ configure(cb_t *cb)
ulong size, bar;
int memindex, ioindex;
+ pcicfgw16(pci, PciPCR,
+ pcicfgr16(pci, PciPCR) & ~(PciPCR_IO|PciPCR_MEM));
+
/* Treat the found device as an ordinary PCI card. It seems that the
CIS is not always present in CardBus cards. XXX, need to support
multifunction cards */
@@ 711,12 713,15 @@ configure(cb_t *cb)
continue;
}
bar = ioreserve(-1, pci->mem[i].size, 0, "cardbus");
+
pci->mem[i].bar = bar | 1;
pcicfgw32(pci, PciBAR0 + i * sizeof(ulong),
pci->mem[i].bar);
pcicfgw16(cb->cb_pci, PciCBIBR0 + ioindex * 8, bar);
pcicfgw16(cb->cb_pci, PciCBILR0 + ioindex * 8,
bar + pci->mem[i].size - 1);
+ //print("ioindex[%d] %.8uX (%d)\n",
+ // ioindex, bar, pci->mem[i].size);
ioindex++;
continue;
}
@@ 740,6 745,8 @@ configure(cb_t *cb)
pcicfgr16(cb->cb_pci, PciBCR) |
(1 << (8 + memindex)));
+ //print("memindex[%d] %.8uX (%d)\n",
+ // memindex, bar, pci->mem[i].size);
memindex++;
}
@@ 507,6 507,279 @@ pciscan(int bno, Pcidev **list)
return ubn;
}
+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.
+
+static void
+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
pcicfginit(void)
{
@@ 610,6 883,9 @@ pcicfginit(void)
qunlock(&pcicfginitlock);
return;
}
+
+ pcirouting();
+
out:
qunlock(&pcicfginitlock);
}