|
@@ -87,3 +87,124 @@ conf_read(unsigned long addr, unsigned char type1,
|
|
|
struct pci_controller *hose)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
|
|
|
+ unsigned int stat0, value, cpu;
|
|
|
+
|
|
|
+ cpu = smp_processor_id();
|
|
|
+
|
|
|
+ local_irq_save(flags);
|
|
|
+
|
|
|
+ DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n",
|
|
|
+ addr, type1, mid));
|
|
|
+
|
|
|
+ /* Reset status register to avoid losing errors. */
|
|
|
+ stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
|
|
|
+ *(vuip)MCPCIA_CAP_ERR(mid) = stat0;
|
|
|
+ mb();
|
|
|
+ *(vuip)MCPCIA_CAP_ERR(mid);
|
|
|
+ DBG_CFG(("conf_read: MCPCIA_CAP_ERR(%d) was 0x%x\n", mid, stat0));
|
|
|
+
|
|
|
+ mb();
|
|
|
+ draina();
|
|
|
+ mcheck_expected(cpu) = 1;
|
|
|
+ mcheck_taken(cpu) = 0;
|
|
|
+ mcheck_extra(cpu) = mid;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+ value = *((vuip)addr);
|
|
|
+ mb();
|
|
|
+ mb(); /* magic */
|
|
|
+
|
|
|
+ if (mcheck_taken(cpu)) {
|
|
|
+ mcheck_taken(cpu) = 0;
|
|
|
+ value = 0xffffffffU;
|
|
|
+ mb();
|
|
|
+ }
|
|
|
+ mcheck_expected(cpu) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ DBG_CFG(("conf_read(): finished\n"));
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+conf_write(unsigned long addr, unsigned int value, unsigned char type1,
|
|
|
+ struct pci_controller *hose)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
|
|
|
+ unsigned int stat0, cpu;
|
|
|
+
|
|
|
+ cpu = smp_processor_id();
|
|
|
+
|
|
|
+ local_irq_save(flags); /* avoid getting hit by machine check */
|
|
|
+
|
|
|
+ /* Reset status register to avoid losing errors. */
|
|
|
+ stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
|
|
|
+ *(vuip)MCPCIA_CAP_ERR(mid) = stat0; mb();
|
|
|
+ *(vuip)MCPCIA_CAP_ERR(mid);
|
|
|
+ DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", mid, stat0));
|
|
|
+
|
|
|
+ draina();
|
|
|
+ mcheck_expected(cpu) = 1;
|
|
|
+ mcheck_extra(cpu) = mid;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ /* Access configuration space. */
|
|
|
+ *((vuip)addr) = value;
|
|
|
+ mb();
|
|
|
+ mb(); /* magic */
|
|
|
+ *(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */
|
|
|
+ mcheck_expected(cpu) = 0;
|
|
|
+ mb();
|
|
|
+
|
|
|
+ DBG_CFG(("conf_write(): finished\n"));
|
|
|
+ local_irq_restore(flags);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where,
|
|
|
+ struct pci_controller *hose, unsigned long *pci_addr,
|
|
|
+ unsigned char *type1)
|
|
|
+{
|
|
|
+ u8 bus = pbus->number;
|
|
|
+ unsigned long addr;
|
|
|
+
|
|
|
+ DBG_CFG(("mk_conf_addr(bus=%d,devfn=0x%x,hose=%d,where=0x%x,"
|
|
|
+ " pci_addr=0x%p, type1=0x%p)\n",
|
|
|
+ bus, devfn, hose->index, where, pci_addr, type1));
|
|
|
+
|
|
|
+ /* Type 1 configuration cycle for *ALL* busses. */
|
|
|
+ *type1 = 1;
|
|
|
+
|
|
|
+ if (!pbus->parent) /* No parent means peer PCI bus. */
|
|
|
+ bus = 0;
|
|
|
+ addr = (bus << 16) | (devfn << 8) | (where);
|
|
|
+ addr <<= 5; /* swizzle for SPARSE */
|
|
|
+ addr |= hose->config_space_base;
|
|
|
+
|
|
|
+ *pci_addr = addr;
|
|
|
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+mcpcia_read_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
|
+ int size, u32 *value)
|
|
|
+{
|
|
|
+ struct pci_controller *hose = bus->sysdata;
|
|
|
+ unsigned long addr, w;
|
|
|
+ unsigned char type1;
|
|
|
+
|
|
|
+ if (mk_conf_addr(bus, devfn, where, hose, &addr, &type1))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ addr |= (size - 1) * 8;
|
|
|
+ w = conf_read(addr, type1, hose);
|
|
|
+ switch (size) {
|
|
|
+ case 1:
|
|
|
+ *value = __kernel_extbl(w, where & 3);
|
|
|
+ break;
|