|
@@ -90,3 +90,88 @@
|
|
|
|
|
|
static int
|
|
|
mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
|
|
|
+ unsigned long *pci_addr, unsigned char *type1)
|
|
|
+{
|
|
|
+ unsigned long addr;
|
|
|
+ u8 bus = pbus->number;
|
|
|
+
|
|
|
+ DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
|
|
|
+ " pci_addr=0x%p, type1=0x%p)\n",
|
|
|
+ bus, device_fn, where, pci_addr, type1));
|
|
|
+
|
|
|
+ if (bus == 0) {
|
|
|
+ int device = device_fn >> 3;
|
|
|
+
|
|
|
+ /* type 0 configuration cycle: */
|
|
|
+
|
|
|
+ if (device > 20) {
|
|
|
+ DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n",
|
|
|
+ device));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ *type1 = 0;
|
|
|
+ addr = (device_fn << 8) | (where);
|
|
|
+ } else {
|
|
|
+ /* type 1 configuration cycle: */
|
|
|
+ *type1 = 1;
|
|
|
+ addr = (bus << 16) | (device_fn << 8) | (where);
|
|
|
+ }
|
|
|
+ *pci_addr = addr;
|
|
|
+ DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+conf_read(unsigned long addr, unsigned char type1)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned int stat0, value;
|
|
|
+ unsigned int haxr2 = 0;
|
|
|
+
|
|
|
+ local_irq_save(flags); /* avoid getting hit by machine check */
|
|
|
+
|
|
|
+ DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
|
|
|
+
|
|
|
+ /* Reset status register to avoid losing errors. */
|
|
|
+ stat0 = *(vuip)APECS_IOC_DCSR;
|
|
|
+ *(vuip)APECS_IOC_DCSR = stat0;
|
|
|
+ mb();
|
|
|
+ DBGC(("conf_read: APECS DCSR was 0x%x\n", stat0));
|
|
|
+
|
|
|
+ /* If Type1 access, must set HAE #2. */
|
|
|
+ if (type1) {
|
|
|
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
|
|
|
+ mb();
|
|
|
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
|
|
|
+ DBGC(("conf_read: TYPE1 access\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ draina();
|
|
|
+ mcheck_expected(0) = 1;
|
|
|
+ mcheck_taken(0) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+
|
|
|
+ /* Some SRMs step on these registers during a machine check. */
|
|
|
+ asm volatile("ldl %0,%1; mb; mb" : "=r"(value) : "m"(*(vuip)addr)
|
|
|
+ : "$9", "$10", "$11", "$12", "$13", "$14", "memory");
|
|
|
+
|
|
|
+ if (mcheck_taken(0)) {
|
|
|
+ mcheck_taken(0) = 0;
|
|
|
+ value = 0xffffffffU;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ mcheck_expected(0) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+#if 1
|
|
|
+ /*
|
|
|
+ * david.rusling@reo.mts.dec.com. This code is needed for the
|
|
|
+ * EB64+ as it does not generate a machine check (why I don't
|
|
|
+ * know). When we build kernels for one particular platform
|
|
|
+ * then we can make this conditional on the type.
|
|
|
+ */
|
|
|
+ draina();
|
|
|
+
|