|
@@ -175,3 +175,153 @@ conf_read(unsigned long addr, unsigned char type1)
|
|
|
*/
|
|
|
draina();
|
|
|
|
|
|
+ /* Now look for any errors. */
|
|
|
+ stat0 = *(vuip)APECS_IOC_DCSR;
|
|
|
+ DBGC(("conf_read: APECS DCSR after read 0x%x\n", stat0));
|
|
|
+
|
|
|
+ /* Is any error bit set? */
|
|
|
+ if (stat0 & 0xffe0U) {
|
|
|
+ /* If not NDEV, print status. */
|
|
|
+ if (!(stat0 & 0x0800)) {
|
|
|
+ printk("apecs.c:conf_read: got stat0=%x\n", stat0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Reset error status. */
|
|
|
+ *(vuip)APECS_IOC_DCSR = stat0;
|
|
|
+ mb();
|
|
|
+ wrmces(0x7); /* reset machine check */
|
|
|
+ value = 0xffffffff;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* If Type1 access, must reset HAE #2 so normal IO space ops work. */
|
|
|
+ if (type1) {
|
|
|
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ local_irq_restore(flags);
|
|
|
+
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned int stat0;
|
|
|
+ unsigned int haxr2 = 0;
|
|
|
+
|
|
|
+ local_irq_save(flags); /* avoid getting hit by machine check */
|
|
|
+
|
|
|
+ /* Reset status register to avoid losing errors. */
|
|
|
+ stat0 = *(vuip)APECS_IOC_DCSR;
|
|
|
+ *(vuip)APECS_IOC_DCSR = stat0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* If Type1 access, must set HAE #2. */
|
|
|
+ if (type1) {
|
|
|
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
|
|
|
+ mb();
|
|
|
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ draina();
|
|
|
+ mcheck_expected(0) = 1;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+ *(vuip)addr = value;
|
|
|
+ mb();
|
|
|
+ mb(); /* magic */
|
|
|
+ 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();
|
|
|
+
|
|
|
+ /* Now look for any errors. */
|
|
|
+ stat0 = *(vuip)APECS_IOC_DCSR;
|
|
|
+
|
|
|
+ /* Is any error bit set? */
|
|
|
+ if (stat0 & 0xffe0U) {
|
|
|
+ /* If not NDEV, print status. */
|
|
|
+ if (!(stat0 & 0x0800)) {
|
|
|
+ printk("apecs.c:conf_write: got stat0=%x\n", stat0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Reset error status. */
|
|
|
+ *(vuip)APECS_IOC_DCSR = stat0;
|
|
|
+ mb();
|
|
|
+ wrmces(0x7); /* reset machine check */
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* If Type1 access, must reset HAE #2 so normal IO space ops work. */
|
|
|
+ if (type1) {
|
|
|
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ local_irq_restore(flags);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+apecs_read_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
|
+ int size, u32 *value)
|
|
|
+{
|
|
|
+ unsigned long addr, pci_addr;
|
|
|
+ unsigned char type1;
|
|
|
+ long mask;
|
|
|
+ int shift;
|
|
|
+
|
|
|
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ mask = (size - 1) * 8;
|
|
|
+ shift = (where & 3) * 8;
|
|
|
+ addr = (pci_addr << 5) + mask + APECS_CONF;
|
|
|
+ *value = conf_read(addr, type1) >> (shift);
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+apecs_write_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
|
+ int size, u32 value)
|
|
|
+{
|
|
|
+ unsigned long addr, pci_addr;
|
|
|
+ unsigned char type1;
|
|
|
+ long mask;
|
|
|
+
|
|
|
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ mask = (size - 1) * 8;
|
|
|
+ addr = (pci_addr << 5) + mask + APECS_CONF;
|
|
|
+ conf_write(addr, value << ((where & 3) * 8), type1);
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+struct pci_ops apecs_pci_ops =
|
|
|
+{
|
|
|
+ .read = apecs_read_config,
|
|
|
+ .write = apecs_write_config,
|
|
|
+};
|
|
|
+
|
|
|
+void
|
|
|
+apecs_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
|
|
|
+{
|
|
|
+ wmb();
|
|
|
+ *(vip)APECS_IOC_TBIA = 0;
|
|
|
+ mb();
|
|
|
+}
|
|
|
+
|
|
|
+void __init
|
|
|
+apecs_init_arch(void)
|
|
|
+{
|
|
|
+ struct pci_controller *hose;
|
|
|
+
|