|
@@ -131,3 +131,127 @@ conf_read(unsigned long addr, unsigned char type1)
|
|
|
mcheck_taken(0) = 0;
|
|
|
mb();
|
|
|
|
|
|
+ /* Access configuration space. */
|
|
|
+ value = *(vip)addr;
|
|
|
+ mb();
|
|
|
+ mb(); /* magic */
|
|
|
+ if (mcheck_taken(0)) {
|
|
|
+ mcheck_taken(0) = 0;
|
|
|
+ value = 0xffffffff;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ mcheck_expected(0) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
|
|
|
+ if (type1) {
|
|
|
+ *(vip)CIA_IOC_CFG = cia_cfg;
|
|
|
+ mb();
|
|
|
+ *(vip)CIA_IOC_CFG;
|
|
|
+ }
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+ DBGC(("done\n"));
|
|
|
+
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ int stat0, cia_cfg = 0;
|
|
|
+
|
|
|
+ DBGC(("conf_write(addr=0x%lx, type1=%d) ", addr, type1));
|
|
|
+ local_irq_save(flags);
|
|
|
+
|
|
|
+ /* Reset status register to avoid losing errors. */
|
|
|
+ stat0 = *(vip)CIA_IOC_CIA_ERR;
|
|
|
+ *(vip)CIA_IOC_CIA_ERR = stat0;
|
|
|
+ mb();
|
|
|
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */
|
|
|
+
|
|
|
+ /* If Type1 access, must set CIA CFG. */
|
|
|
+ if (type1) {
|
|
|
+ cia_cfg = *(vip)CIA_IOC_CFG;
|
|
|
+ *(vip)CIA_IOC_CFG = (cia_cfg & ~3) | 1;
|
|
|
+ mb();
|
|
|
+ *(vip)CIA_IOC_CFG;
|
|
|
+ }
|
|
|
+
|
|
|
+ mb();
|
|
|
+ draina();
|
|
|
+ mcheck_expected(0) = 1;
|
|
|
+ mcheck_taken(0) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+ *(vip)addr = value;
|
|
|
+ mb();
|
|
|
+ *(vip)addr; /* read back to force the write */
|
|
|
+
|
|
|
+ mcheck_expected(0) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
|
|
|
+ if (type1) {
|
|
|
+ *(vip)CIA_IOC_CFG = cia_cfg;
|
|
|
+ mb();
|
|
|
+ *(vip)CIA_IOC_CFG;
|
|
|
+ }
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+ DBGC(("done\n"));
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+cia_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
|
|
|
+ u32 *value)
|
|
|
+{
|
|
|
+ unsigned long addr, pci_addr;
|
|
|
+ long mask;
|
|
|
+ unsigned char type1;
|
|
|
+ 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 + CIA_CONF;
|
|
|
+ *value = conf_read(addr, type1) >> (shift);
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+cia_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
|
|
|
+ u32 value)
|
|
|
+{
|
|
|
+ unsigned long addr, pci_addr;
|
|
|
+ long mask;
|
|
|
+ unsigned char type1;
|
|
|
+
|
|
|
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ mask = (size - 1) * 8;
|
|
|
+ addr = (pci_addr << 5) + mask + CIA_CONF;
|
|
|
+ conf_write(addr, value << ((where & 3) * 8), type1);
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+struct pci_ops cia_pci_ops =
|
|
|
+{
|
|
|
+ .read = cia_read_config,
|
|
|
+ .write = cia_write_config,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * CIA Pass 1 and PYXIS Pass 1 and 2 have a broken scatter-gather tlb.
|
|
|
+ * It cannot be invalidated. Rather than hard code the pass numbers,
|
|
|
+ * actually try the tbia to see if it works.
|
|
|
+ */
|
|
|
+
|
|
|
+void
|
|
|
+cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
|
|
|
+{
|