OSDN Git Service

Merge branch 'pci/msi' into next
[uclinux-h8/linux.git] / drivers / pci / host / pcie-designware.c
index 1eaf4df..f727445 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pci_regs.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #include "pcie-designware.h"
@@ -72,6 +73,8 @@ static unsigned long global_io_offset;
 
 static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 {
+       BUG_ON(!sys->private_data);
+
        return sys->private_data;
 }
 
@@ -217,34 +220,49 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
        return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val &= ~(1 << bit);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
                            unsigned int nvec, unsigned int pos)
 {
-       unsigned int i, res, bit, val;
+       unsigned int i;
 
        for (i = 0; i < nvec; i++) {
                irq_set_msi_desc_off(irq_base, i, NULL);
                clear_bit(pos + i, pp->msi_irq_in_use);
                /* Disable corresponding interrupt on MSI controller */
-               res = ((pos + i) / 32) * 12;
-               bit = (pos + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val &= ~(1 << bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_clear_irq)
+                       pp->ops->msi_clear_irq(pp, pos + i);
+               else
+                       dw_pcie_msi_clear_irq(pp, pos + i);
        }
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val |= 1 << bit;
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-       int res, bit, irq, pos0, pos1, i;
-       u32 val;
+       int irq, pos0, pos1, i;
        struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
-       if (!pp) {
-               BUG();
-               return -EINVAL;
-       }
-
        pos0 = find_first_zero_bit(pp->msi_irq_in_use,
                        MAX_MSI_IRQS);
        if (pos0 % no_irqs) {
@@ -281,11 +299,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
                }
                set_bit(pos0 + i, pp->msi_irq_in_use);
                /*Enable corresponding interrupt in MSI interrupt controller */
-               res = ((pos0 + i) / 32) * 12;
-               bit = (pos0 + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val |= 1 << bit;
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_set_irq)
+                       pp->ops->msi_set_irq(pp, pos0 + i);
+               else
+                       dw_pcie_msi_set_irq(pp, pos0 + i);
        }
 
        *pos = pos0;
@@ -306,10 +323,6 @@ static void clear_irq(unsigned int irq)
        /* get the port structure */
        msi = irq_data_get_msi(data);
        pp = sys_to_pcie(msi->dev->bus->sysdata);
-       if (!pp) {
-               BUG();
-               return;
-       }
 
        /* undo what was done in assign_irq */
        pos = data->hwirq;
@@ -330,14 +343,8 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
        struct msi_msg msg;
        struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
 
-       if (!pp) {
-               BUG();
-               return -EINVAL;
-       }
-
-       pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
-                               &msg_ctr);
-       msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
+       pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &msg_ctr);
+       msgvec = (msg_ctr & PCI_MSI_FLAGS_QSIZE) >> 4;
        if (msgvec == 0)
                msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
        if (msgvec > 5)
@@ -353,9 +360,17 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
         */
        desc->msi_attrib.multiple = msgvec;
 
-       msg.address_lo = virt_to_phys((void *)pp->msi_data);
+       if (pp->ops->get_msi_addr)
+               msg.address_lo = pp->ops->get_msi_addr(pp);
+       else
+               msg.address_lo = virt_to_phys((void *)pp->msi_data);
        msg.address_hi = 0x0;
-       msg.data = pos;
+
+       if (pp->ops->get_msi_data)
+               msg.data = pp->ops->get_msi_data(pp, pos);
+       else
+               msg.data = pos;
+
        write_msi_msg(irq, &msg);
 
        return 0;
@@ -396,10 +411,35 @@ static const struct irq_domain_ops msi_domain_ops = {
 int __init dw_pcie_host_init(struct pcie_port *pp)
 {
        struct device_node *np = pp->dev->of_node;
+       struct platform_device *pdev = to_platform_device(pp->dev);
        struct of_pci_range range;
        struct of_pci_range_parser parser;
-       u32 val;
-       int i;
+       struct resource *cfg_res;
+       u32 val, na, ns;
+       const __be32 *addrp;
+       int i, index, ret;
+
+       /* Find the address cell size and the number of cells in order to get
+        * the untranslated address.
+        */
+       of_property_read_u32(np, "#address-cells", &na);
+       ns = of_n_size_cells(np);
+
+       cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+       if (cfg_res) {
+               pp->cfg0_size = resource_size(cfg_res)/2;
+               pp->cfg1_size = resource_size(cfg_res)/2;
+               pp->cfg0_base = cfg_res->start;
+               pp->cfg1_base = cfg_res->start + pp->cfg0_size;
+
+               /* Find the untranslated configuration space address */
+               index = of_property_match_string(np, "reg-names", "config");
+               addrp = of_get_address(np, index, NULL, NULL);
+               pp->cfg0_mod_base = of_read_number(addrp, ns);
+               pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size;
+       } else {
+               dev_err(pp->dev, "missing *config* reg space\n");
+       }
 
        if (of_pci_range_parser_init(&parser, np)) {
                dev_err(pp->dev, "missing ranges property\n");
@@ -418,24 +458,50 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                        pp->io.end = min_t(resource_size_t,
                                           IO_SPACE_LIMIT,
                                           range.pci_addr + range.size
-                                          + global_io_offset);
-                       pp->config.io_size = resource_size(&pp->io);
-                       pp->config.io_bus_addr = range.pci_addr;
+                                          + global_io_offset - 1);
+                       pp->io_size = resource_size(&pp->io);
+                       pp->io_bus_addr = range.pci_addr;
                        pp->io_base = range.cpu_addr;
+
+                       /* Find the untranslated IO space address */
+                       pp->io_mod_base = of_read_number(parser.range -
+                                                        parser.np + na, ns);
                }
                if (restype == IORESOURCE_MEM) {
                        of_pci_range_to_resource(&range, np, &pp->mem);
                        pp->mem.name = "MEM";
-                       pp->config.mem_size = resource_size(&pp->mem);
-                       pp->config.mem_bus_addr = range.pci_addr;
+                       pp->mem_size = resource_size(&pp->mem);
+                       pp->mem_bus_addr = range.pci_addr;
+
+                       /* Find the untranslated MEM space address */
+                       pp->mem_mod_base = of_read_number(parser.range -
+                                                         parser.np + na, ns);
                }
                if (restype == 0) {
                        of_pci_range_to_resource(&range, np, &pp->cfg);
-                       pp->config.cfg0_size = resource_size(&pp->cfg)/2;
-                       pp->config.cfg1_size = resource_size(&pp->cfg)/2;
+                       pp->cfg0_size = resource_size(&pp->cfg)/2;
+                       pp->cfg1_size = resource_size(&pp->cfg)/2;
+                       pp->cfg0_base = pp->cfg.start;
+                       pp->cfg1_base = pp->cfg.start + pp->cfg0_size;
+
+                       /* Find the untranslated configuration space address */
+                       pp->cfg0_mod_base = of_read_number(parser.range -
+                                                          parser.np + na, ns);
+                       pp->cfg1_mod_base = pp->cfg0_mod_base +
+                                           pp->cfg0_size;
                }
        }
 
+       ret = of_pci_parse_bus_range(np, &pp->busn);
+       if (ret < 0) {
+               pp->busn.name = np->name;
+               pp->busn.start = 0;
+               pp->busn.end = 0xff;
+               pp->busn.flags = IORESOURCE_BUS;
+               dev_dbg(pp->dev, "failed to parse bus-range property: %d, using default %pR\n",
+                       ret, &pp->busn);
+       }
+
        if (!pp->dbi_base) {
                pp->dbi_base = devm_ioremap(pp->dev, pp->cfg.start,
                                        resource_size(&pp->cfg));
@@ -445,21 +511,24 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       pp->cfg0_base = pp->cfg.start;
-       pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
        pp->mem_base = pp->mem.start;
 
-       pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-                                       pp->config.cfg0_size);
        if (!pp->va_cfg0_base) {
-               dev_err(pp->dev, "error with ioremap in function\n");
-               return -ENOMEM;
+               pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+                                               pp->cfg0_size);
+               if (!pp->va_cfg0_base) {
+                       dev_err(pp->dev, "error with ioremap in function\n");
+                       return -ENOMEM;
+               }
        }
-       pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-                                       pp->config.cfg1_size);
+
        if (!pp->va_cfg1_base) {
-               dev_err(pp->dev, "error with ioremap\n");
-               return -ENOMEM;
+               pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+                                               pp->cfg1_size);
+               if (!pp->va_cfg1_base) {
+                       dev_err(pp->dev, "error with ioremap\n");
+                       return -ENOMEM;
+               }
        }
 
        if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
@@ -468,16 +537,22 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
        }
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
-               pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-                                       MAX_MSI_IRQS, &msi_domain_ops,
-                                       &dw_pcie_msi_chip);
-               if (!pp->irq_domain) {
-                       dev_err(pp->dev, "irq domain init failed\n");
-                       return -ENXIO;
-               }
+               if (!pp->ops->msi_host_init) {
+                       pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
+                                               MAX_MSI_IRQS, &msi_domain_ops,
+                                               &dw_pcie_msi_chip);
+                       if (!pp->irq_domain) {
+                               dev_err(pp->dev, "irq domain init failed\n");
+                               return -ENXIO;
+                       }
 
-               for (i = 0; i < MAX_MSI_IRQS; i++)
-                       irq_create_mapping(pp->irq_domain, i);
+                       for (i = 0; i < MAX_MSI_IRQS; i++)
+                               irq_create_mapping(pp->irq_domain, i);
+               } else {
+                       ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+                       if (ret < 0)
+                               return ret;
+               }
        }
 
        if (pp->ops->host_init)
@@ -496,7 +571,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
        dw_pci.private_data = (void **)&pp;
 
        pci_common_init_dev(pp->dev, &dw_pci);
-       pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
        dw_pci.domain++;
 #endif
@@ -509,9 +583,9 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
        /* Program viewport 0 : OUTBOUND : CFG0 */
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
-       dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->cfg0_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -525,9 +599,9 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->cfg1_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -540,12 +614,12 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
+       dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->mem_size - 1,
                          PCIE_ATU_LIMIT);
-       dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
-       dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
+       dw_pcie_writel_rc(pp, pp->mem_bus_addr, PCIE_ATU_LOWER_TARGET);
+       dw_pcie_writel_rc(pp, upper_32_bits(pp->mem_bus_addr),
                          PCIE_ATU_UPPER_TARGET);
        dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
 }
@@ -556,12 +630,12 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
+       dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->io_mod_base + pp->io_size - 1,
                          PCIE_ATU_LIMIT);
-       dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
-       dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
+       dw_pcie_writel_rc(pp, pp->io_bus_addr, PCIE_ATU_LOWER_TARGET);
+       dw_pcie_writel_rc(pp, upper_32_bits(pp->io_bus_addr),
                          PCIE_ATU_UPPER_TARGET);
        dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
 }
@@ -645,18 +719,17 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
        struct pcie_port *pp = sys_to_pcie(bus->sysdata);
        int ret;
 
-       if (!pp) {
-               BUG();
-               return -EINVAL;
-       }
-
        if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
                *val = 0xffffffff;
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+               if (pp->ops->rd_other_conf)
+                       ret = pp->ops->rd_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_rd_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -670,16 +743,15 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
        struct pcie_port *pp = sys_to_pcie(bus->sysdata);
        int ret;
 
-       if (!pp) {
-               BUG();
-               return -EINVAL;
-       }
-
        if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+               if (pp->ops->wr_other_conf)
+                       ret = pp->ops->wr_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_wr_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_wr_own_conf(pp, where, size, val);
@@ -698,19 +770,17 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
 
        pp = sys_to_pcie(sys);
 
-       if (!pp)
-               return 0;
-
-       if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
-               sys->io_offset = global_io_offset - pp->config.io_bus_addr;
+       if (global_io_offset < SZ_1M && pp->io_size > 0) {
+               sys->io_offset = global_io_offset - pp->io_bus_addr;
                pci_ioremap_io(global_io_offset, pp->io_base);
                global_io_offset += SZ_64K;
                pci_add_resource_offset(&sys->resources, &pp->io,
                                        sys->io_offset);
        }
 
-       sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr;
+       sys->mem_offset = pp->mem.start - pp->mem_bus_addr;
        pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset);
+       pci_add_resource(&sys->resources, &pp->busn);
 
        return 1;
 }
@@ -720,14 +790,16 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        struct pci_bus *bus;
        struct pcie_port *pp = sys_to_pcie(sys);
 
-       if (pp) {
-               pp->root_bus_nr = sys->busnr;
-               bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops,
-                                       sys, &sys->resources);
-       } else {
-               bus = NULL;
-               BUG();
-       }
+       pp->root_bus_nr = sys->busnr;
+       bus = pci_create_root_bus(pp->dev, sys->busnr,
+                                 &dw_pcie_ops, sys, &sys->resources);
+       if (!bus)
+               return NULL;
+
+       pci_scan_child_bus(bus);
+
+       if (bus && pp->ops->scan_bus)
+               pp->ops->scan_bus(pp);
 
        return bus;
 }
@@ -763,7 +835,6 @@ static struct hw_pci dw_pci = {
 
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
-       struct pcie_port_info *config = &pp->config;
        u32 val;
        u32 membase;
        u32 memlimit;
@@ -818,7 +889,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 
        /* setup memory base, memory limit */
        membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
-       memlimit = (config->mem_size + (u32)pp->mem_base) & 0xfff00000;
+       memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
        val = memlimit | membase;
        dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);