+
+static u8 iseries_readb(const volatile void __iomem *addr)
+{
+ return iSeries_Read_Byte(addr);
+}
+
+static u16 iseries_readw(const volatile void __iomem *addr)
+{
+ return le16_to_cpu(iSeries_Read_Word(addr));
+}
+
+static u32 iseries_readl(const volatile void __iomem *addr)
+{
+ return le32_to_cpu(iSeries_Read_Long(addr));
+}
+
+static u16 iseries_readw_be(const volatile void __iomem *addr)
+{
+ return iSeries_Read_Word(addr);
+}
+
+static u32 iseries_readl_be(const volatile void __iomem *addr)
+{
+ return iSeries_Read_Long(addr);
+}
+
+static void iseries_writeb(u8 data, volatile void __iomem *addr)
+{
+ iSeries_Write_Byte(data, addr);
+}
+
+static void iseries_writew(u16 data, volatile void __iomem *addr)
+{
+ iSeries_Write_Word(cpu_to_le16(data), addr);
+}
+
+static void iseries_writel(u32 data, volatile void __iomem *addr)
+{
+ iSeries_Write_Long(cpu_to_le32(data), addr);
+}
+
+static void iseries_writew_be(u16 data, volatile void __iomem *addr)
+{
+ iSeries_Write_Word(data, addr);
+}
+
+static void iseries_writel_be(u32 data, volatile void __iomem *addr)
+{
+ iSeries_Write_Long(data, addr);
+}
+
+static void iseries_readsb(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ u8 *dst = buf;
+ while(count-- > 0)
+ *(dst++) = iSeries_Read_Byte(addr);
+}
+
+static void iseries_readsw(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ u16 *dst = buf;
+ while(count-- > 0)
+ *(dst++) = iSeries_Read_Word(addr);
+}
+
+static void iseries_readsl(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ u32 *dst = buf;
+ while(count-- > 0)
+ *(dst++) = iSeries_Read_Long(addr);
+}
+
+static void iseries_writesb(volatile void __iomem *addr, const void *buf,
+ unsigned long count)
+{
+ const u8 *src = buf;
+ while(count-- > 0)
+ iSeries_Write_Byte(*(src++), addr);
+}
+
+static void iseries_writesw(volatile void __iomem *addr, const void *buf,
+ unsigned long count)
+{
+ const u16 *src = buf;
+ while(count-- > 0)
+ iSeries_Write_Word(*(src++), addr);
+}
+
+static void iseries_writesl(volatile void __iomem *addr, const void *buf,
+ unsigned long count)
+{
+ const u32 *src = buf;
+ while(count-- > 0)
+ iSeries_Write_Long(*(src++), addr);
+}
+
+static void iseries_memset_io(volatile void __iomem *addr, int c,
+ unsigned long n)
+{
+ volatile char __iomem *d = addr;
+
+ while (n-- > 0)
+ iSeries_Write_Byte(c, d++);
+}
+
+static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n)
+{
+ char *d = dest;
+ const volatile char __iomem *s = src;
+
+ while (n-- > 0)
+ *d++ = iSeries_Read_Byte(s++);
+}
+
+static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
+ unsigned long n)
+{
+ const char *s = src;
+ volatile char __iomem *d = dest;
+
+ while (n-- > 0)
+ iSeries_Write_Byte(*s++, d++);
+}
+
+/* We only set MMIO ops. The default PIO ops will be default
+ * to the MMIO ops + pci_io_base which is 0 on iSeries as
+ * expected so both should work.
+ *
+ * Note that we don't implement the readq/writeq versions as
+ * I don't know of an HV call for doing so. Thus, the default
+ * operation will be used instead, which will fault a the value
+ * return by iSeries for MMIO addresses always hits a non mapped
+ * area. This is as good as the BUG() we used to have there.
+ */
+static struct ppc_pci_io __initdata iseries_pci_io = {
+ .readb = iseries_readb,
+ .readw = iseries_readw,
+ .readl = iseries_readl,
+ .readw_be = iseries_readw_be,
+ .readl_be = iseries_readl_be,
+ .writeb = iseries_writeb,
+ .writew = iseries_writew,
+ .writel = iseries_writel,
+ .writew_be = iseries_writew_be,
+ .writel_be = iseries_writel_be,
+ .readsb = iseries_readsb,
+ .readsw = iseries_readsw,
+ .readsl = iseries_readsl,
+ .writesb = iseries_writesb,
+ .writesw = iseries_writesw,
+ .writesl = iseries_writesl,
+ .memset_io = iseries_memset_io,
+ .memcpy_fromio = iseries_memcpy_fromio,
+ .memcpy_toio = iseries_memcpy_toio,
+};
+
+/*
+ * iSeries_pcibios_init
+ *
+ * Description:
+ * This function checks for all possible system PCI host bridges that connect
+ * PCI buses. The system hypervisor is queried as to the guest partition
+ * ownership status. A pci_controller is built for any bus which is partially
+ * owned or fully owned by this guest partition.
+ */
+void __init iSeries_pcibios_init(void)
+{
+ struct pci_controller *phb;
+ struct device_node *root = of_find_node_by_path("/");
+ struct device_node *node = NULL;
+
+ /* Install IO hooks */
+ ppc_pci_io = iseries_pci_io;
+
+ if (root == NULL) {
+ printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
+ "of device tree\n");
+ return;
+ }
+ while ((node = of_get_next_child(root, node)) != NULL) {
+ HvBusNumber bus;
+ const u32 *busp;
+
+ if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+ continue;
+
+ busp = get_property(node, "bus-range", NULL);
+ if (busp == NULL)
+ continue;
+ bus = *busp;
+ printk("bus %d appears to exist\n", bus);
+ phb = pcibios_alloc_controller(node);
+ if (phb == NULL)
+ continue;
+
+ phb->pci_mem_offset = phb->local_number = bus;
+ phb->first_busno = bus;
+ phb->last_busno = bus;
+ phb->ops = &iSeries_pci_ops;
+ }
+
+ of_node_put(root);
+
+ pci_devs_phb_init();
+}
+