|
@@ -157,3 +157,84 @@ mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
|
|
|
device));
|
|
|
return -1;
|
|
|
}
|
|
|
+
|
|
|
+ *type1 = 0;
|
|
|
+ addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
|
|
|
+ } else {
|
|
|
+ /* Type 1 configuration cycle. */
|
|
|
+ *type1 = 1;
|
|
|
+ addr = (bus << 16) | (device_fn << 8) | (where);
|
|
|
+ }
|
|
|
+ *pci_addr = addr;
|
|
|
+ DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * NOTE: both conf_read() and conf_write() may set HAE_3 when needing
|
|
|
+ * to do type1 access. This is protected by the use of spinlock IRQ
|
|
|
+ * primitives in the wrapper functions pci_{read,write}_config_*()
|
|
|
+ * defined in drivers/pci/pci.c.
|
|
|
+ */
|
|
|
+static unsigned int
|
|
|
+conf_read(unsigned long addr, unsigned char type1)
|
|
|
+{
|
|
|
+ unsigned int value, cpu, taken;
|
|
|
+ unsigned long t2_cfg = 0;
|
|
|
+
|
|
|
+ cpu = smp_processor_id();
|
|
|
+
|
|
|
+ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
|
|
|
+
|
|
|
+ /* If Type1 access, must set T2 CFG. */
|
|
|
+ if (type1) {
|
|
|
+ t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
|
|
|
+ *(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ mb();
|
|
|
+ draina();
|
|
|
+
|
|
|
+ mcheck_expected(cpu) = 1;
|
|
|
+ mcheck_taken(cpu) = 0;
|
|
|
+ t2_mcheck_any_expected |= (1 << cpu);
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+ value = *(vuip)addr;
|
|
|
+ mb();
|
|
|
+ mb(); /* magic */
|
|
|
+
|
|
|
+ /* Wait for possible mcheck. Also, this lets other CPUs clear
|
|
|
+ their mchecks as well, as they can reliably tell when
|
|
|
+ another CPU is in the midst of handling a real mcheck via
|
|
|
+ the "taken" function. */
|
|
|
+ udelay(100);
|
|
|
+
|
|
|
+ if ((taken = mcheck_taken(cpu))) {
|
|
|
+ mcheck_taken(cpu) = 0;
|
|
|
+ t2_mcheck_last_taken |= (1 << cpu);
|
|
|
+ value = 0xffffffffU;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ mcheck_expected(cpu) = 0;
|
|
|
+ t2_mcheck_any_expected = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* If Type1 access, must reset T2 CFG so normal IO space ops work. */
|
|
|
+ if (type1) {
|
|
|
+ *(vulp)T2_HAE_3 = t2_cfg;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
|
|
|
+{
|
|
|
+ unsigned int cpu, taken;
|
|
|
+ unsigned long t2_cfg = 0;
|
|
|
+
|
|
|
+ cpu = smp_processor_id();
|
|
|
+
|