--- zzzz-none-000/linux-4.4.271/drivers/pci/host/pcie-designware.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/pci/host/pcie-designware.c 2023-04-19 10:22:29.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include "pcie-designware.h" @@ -69,6 +70,21 @@ #define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) #define PCIE_ATU_UPPER_TARGET 0x91C +/* PCIe Port Logic registers */ +#define PLR_OFFSET 0x700 +#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c) +#define PCIE_PHY_DEBUG_R1_LINK_UP 0x00000010 + +#define PCIE_IATU_BASE(n) (n * 0x200) + +#define PCIE_IATU_CTRL1(n) (PCIE_IATU_BASE(n) + 0x00) +#define PCIE_IATU_CTRL2(n) (PCIE_IATU_BASE(n) + 0x04) +#define PCIE_IATU_LBAR(n) (PCIE_IATU_BASE(n) + 0x08) +#define PCIE_IATU_UBAR(n) (PCIE_IATU_BASE(n) + 0x0c) +#define PCIE_IATU_LAR(n) (PCIE_IATU_BASE(n) + 0x10) +#define PCIE_IATU_LTAR(n) (PCIE_IATU_BASE(n) + 0x14) +#define PCIE_IATU_UTAR(n) (PCIE_IATU_BASE(n) + 0x18) + static struct pci_ops dw_pcie_ops; int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val) @@ -128,42 +144,60 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val) { - int ret; - if (pp->ops->rd_own_conf) - ret = pp->ops->rd_own_conf(pp, where, size, val); - else - ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val); + return pp->ops->rd_own_conf(pp, where, size, val); - return ret; + return dw_pcie_cfg_read(pp->dbi_base + where, size, val); } static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val) { - int ret; - if (pp->ops->wr_own_conf) - ret = pp->ops->wr_own_conf(pp, where, size, val); - else - ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val); + return pp->ops->wr_own_conf(pp, where, size, val); - return ret; + return dw_pcie_cfg_write(pp->dbi_base + where, size, val); +} + +static inline void dw_pcie_writel_rc_gen3(struct pcie_port *pp, u32 val, u32 reg) +{ + writel_relaxed(val, pp->dm_iatu + reg); } static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index, int type, u64 cpu_addr, u64 pci_addr, u32 size) { - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1), - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); + if (pp->is_gen3) { + dw_pcie_writel_rc_gen3(pp, 0, PCIE_IATU_CTRL2(index)); + wmb(); + dw_pcie_writel_rc_gen3(pp, type, PCIE_IATU_CTRL1(index)); + dw_pcie_writel_rc_gen3(pp, lower_32_bits(cpu_addr), + PCIE_IATU_LBAR(index)); + dw_pcie_writel_rc_gen3(pp, upper_32_bits(cpu_addr), + PCIE_IATU_UBAR(index)); + dw_pcie_writel_rc_gen3(pp, lower_32_bits(cpu_addr + size - 1), + PCIE_IATU_LAR(index)); + dw_pcie_writel_rc_gen3(pp, lower_32_bits(pci_addr), + PCIE_IATU_LTAR(index)); + dw_pcie_writel_rc_gen3(pp, upper_32_bits(pci_addr), + PCIE_IATU_UTAR(index)); + wmb(); + dw_pcie_writel_rc_gen3(pp, BIT(31), PCIE_IATU_CTRL2(index)); + wmb(); + + } else { + dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index, + PCIE_ATU_VIEWPORT); + dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1), + PCIE_ATU_LIMIT); + dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET); + dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); + + } } static struct irq_chip dw_msi_irq_chip = { @@ -374,18 +408,206 @@ clear_irq_range(pp, irq, 1, data->hwirq); } +static void dw_msi_teardown_irqs(struct msi_desc *msi, struct pcie_port *pp) +{ + struct irq_data *data = irq_get_irq_data(msi->irq); + + clear_irq_range(pp, msi->irq, msi->nvec_used, data->hwirq); +} + +static int pcie_create_qgic_msi_irq(struct pcie_port *dev) +{ + int irq, pos; + +again: + pos = find_first_zero_bit(dev->msi_irq_in_use, MAX_MSI_IRQS); + + if (pos >= MAX_MSI_IRQS) + return -ENOSPC; + + if (test_and_set_bit(pos, dev->msi_irq_in_use)) + goto again; + + if (pos >= MAX_MSI_IRQS) { + printk("PCIe: pos %d is not less than %d\n", + pos, MAX_MSI_IRQS); + return ENOSPC; + } + + irq = dev->msi[pos]; + if (!irq) { + printk("PCIe: failed to create QGIC MSI IRQ.\n"); + return -EINVAL; + } + + return irq; +} + +static int qgic_msi_setup_irq(struct pci_dev *pdev, + struct msi_desc *desc, int nvec) +{ + int irq, index, firstirq = 0; + struct msi_msg msg; + struct pcie_port *dev = pdev->bus->sysdata; + + for (index = 0; index < nvec; index++) { + irq = pcie_create_qgic_msi_irq(dev); + + if (irq < 0) + return irq; + + if (index == 0) + firstirq = irq; + + irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); + } + + /* write msi vector and data */ + irq_set_msi_desc(firstirq, desc); + + msg.address_hi = 0; + msg.address_lo = dev->msi_gicm_addr; + msg.data = dev->msi_gicm_base + (firstirq - dev->msi[0]); + write_msi_msg(firstirq, &msg); + + return 0; +} + +static int msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, + struct msi_desc *desc) +{ + struct pcie_port *pp = pdev->bus->sysdata; + + if (pp->msi_gicm_addr) + return qgic_msi_setup_irq(pdev, desc, 1); + else + return dw_msi_setup_irq(chip, pdev, desc); +} + +int qgic_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct msi_desc *entry; + int ret = 0; + + if (type == PCI_CAP_ID_MSIX) + return -EINVAL; + + /* FIXME: + * AVM/AMY: The whole qgic_msi code looks broken. + * Ie. we don't have proper error handling/cleanup and + * if we don't get consecutive IRQ numbers here by coincidence, + * neither registering IRQs in HW nor teardown will work. + * Warn if we ever use this. + * Otherwise wait for mainline patches. + */ + pr_warn("This code is broken for non consecutive irq numbers!\n"); + list_for_each_entry(entry, &dev->dev.msi_list, list) { + entry->nvec_used = nvec; + entry->msi_attrib.multiple = order_base_2(nvec); + ret = qgic_msi_setup_irq(dev, entry, nvec); + } + + return ret; +} + +static int msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev, + int nvec, int type) +{ + struct pcie_port *pp = pdev->bus->sysdata; + + if (pp->msi_gicm_addr) + return qgic_setup_msi_irqs(pdev, nvec, type); + else + return dw_msi_setup_irqs(chip, pdev, nvec, type); +} + +void pcie_destroy_qgic_msi_irq(unsigned int irq, struct pcie_port *dev) +{ + int pos; + + pos = irq - dev->msi[0]; + clear_bit(pos, dev->msi_irq_in_use); +} + +static void msi_teardown_irq(struct msi_controller *chip, unsigned int irq) +{ + struct irq_data *data = irq_get_irq_data(irq); + struct msi_desc *msi; + struct pcie_port *pp; + + if (data) { + msi = irq_data_get_msi_desc(data); + pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); + + if (pp->msi_gicm_addr) + pcie_destroy_qgic_msi_irq(irq, pp); + else + dw_msi_teardown_irq(chip, irq); + } +} + +static void msi_teardown_irqs(struct pci_dev *dev) +{ + struct msi_desc *entry; + struct pcie_port *pp = dev->bus->sysdata; + + list_for_each_entry(entry, &dev->dev.msi_list, list) { + + if (entry->irq == 0) + continue; + + if (pp->msi_gicm_addr) { + int i; + + for (i = 0; i < entry->nvec_used; i++) + pcie_destroy_qgic_msi_irq(entry->irq + i, pp); + } else { + dw_msi_teardown_irqs(entry, pp); + } + } +} + static struct msi_controller dw_pcie_msi_chip = { - .setup_irq = dw_msi_setup_irq, - .setup_irqs = dw_msi_setup_irqs, - .teardown_irq = dw_msi_teardown_irq, + .setup_irq = msi_setup_irq, + .setup_irqs = msi_setup_irqs, + .teardown_irq = msi_teardown_irq, + .teardown_irqs = msi_teardown_irqs, }; +int dw_pcie_wait_for_link(struct pcie_port *pp) +{ + int retries, max_link_retries; + + if(pp->link_retries_count != 0) + max_link_retries = pp->link_retries_count; + else + max_link_retries = LINK_WAIT_MAX_RETRIES; + + /* check if the link is up or not */ + for (retries = 0; retries < max_link_retries; retries++) { + if (dw_pcie_link_up(pp)) { + dev_info(pp->dev, "link up\n"); + return 0; + } + usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX); + if(pp->use_delay) + mdelay(10000); + } + + dev_err(pp->dev, "phy link never came up\n"); + + return -ETIMEDOUT; +} + int dw_pcie_link_up(struct pcie_port *pp) { + u32 val; + if (pp->ops->link_up) return pp->ops->link_up(pp); - else - return 0; + + val = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1); + return val & PCIE_PHY_DEBUG_R1_LINK_UP; } static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq, @@ -407,17 +629,14 @@ struct platform_device *pdev = to_platform_device(pp->dev); struct pci_bus *bus, *child; struct resource *cfg_res; - u32 val; int i, ret; LIST_HEAD(res); struct resource_entry *win; 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_size = resource_size(cfg_res); pp->cfg0_base = cfg_res->start; - pp->cfg1_base = cfg_res->start + pp->cfg0_size; } else if (!pp->va_cfg0_base) { dev_err(pp->dev, "missing *config* reg space\n"); } @@ -426,6 +645,10 @@ if (ret) return ret; + ret = devm_request_pci_bus_resources(pp->dev, &res); + if (ret) + return ret; + /* Get the I/O and memory ranges from DT */ resource_list_for_each_entry(win, &res) { switch (resource_type(win->res)) { @@ -434,7 +657,7 @@ pp->io->name = "I/O"; pp->io_size = resource_size(pp->io); pp->io_bus_addr = pp->io->start - win->offset; - ret = pci_remap_iospace(pp->io, pp->io_base); + ret = devm_pci_remap_iospace(pp->dev, pp->io, pp->io_base); if (ret) { dev_warn(pp->dev, "error %d: failed to map resource %pR\n", ret, pp->io); @@ -449,10 +672,8 @@ break; case 0: pp->cfg = win->res; - pp->cfg0_size = resource_size(pp->cfg)/2; - pp->cfg1_size = resource_size(pp->cfg)/2; + pp->cfg0_size = resource_size(pp->cfg); pp->cfg0_base = pp->cfg->start; - pp->cfg1_base = pp->cfg->start + pp->cfg0_size; break; case IORESOURCE_BUS: pp->busn = win->res; @@ -482,40 +703,90 @@ } } - if (!pp->va_cfg1_base) { - 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; - } - } - ret = of_property_read_u32(np, "num-lanes", &pp->lanes); if (ret) pp->lanes = 0; if (IS_ENABLED(CONFIG_PCI_MSI)) { - if (!pp->ops->msi_host_init) { - pp->irq_domain = irq_domain_add_linear(pp->dev->of_node, + if (!pp->msi_gicm_addr) { + 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; + 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); + } else { + ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip); + if (ret < 0) + return ret; } + } + } - 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) { + ret = pp->ops->host_init(pp); + if (ret) { + dev_err(pp->dev, "hostinit failed\n"); + return ret; } } - if (pp->ops->host_init) - pp->ops->host_init(pp); + pp->root_bus_nr = pp->busn->start; + if (IS_ENABLED(CONFIG_PCI_MSI)) { + bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr, + &dw_pcie_ops, pp, &res, + &dw_pcie_msi_chip); + dw_pcie_msi_chip.dev = pp->dev; + } else + bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops, + pp, &res); + if (!bus) + return -ENOMEM; + + pp->pci_bus = bus; + if (pp->ops->scan_bus) + pp->ops->scan_bus(pp); + +#ifdef CONFIG_ARM + /* support old dtbs that incorrectly describe IRQs */ + pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); +#endif + + if (!pci_has_flag(PCI_PROBE_ONLY)) { + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + + pci_bus_add_devices(bus); + return 0; +} + +int dw_pcie_host_init_pm(struct pcie_port *pp) +{ + int ret; + LIST_HEAD(res); + u32 val; + struct pci_bus *bus, *child; + + pci_add_resource(&res, pp->busn); + pci_add_resource(&res, pp->io); + pci_add_resource(&res, pp->mem); + + if (pp->ops->host_init) { + ret = pp->ops->host_init(pp); + if (ret) { + dev_err(pp->dev, "pm_hostinit failed\n"); + return ret; + } + } if (!pp->ops->rd_other_conf) dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1, @@ -537,12 +808,14 @@ &dw_pcie_ops, pp, &res, &dw_pcie_msi_chip); dw_pcie_msi_chip.dev = pp->dev; - } else + } else { bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops, pp, &res); + } if (!bus) return -ENOMEM; + pp->pci_bus = bus; if (pp->ops->scan_bus) pp->ops->scan_bus(pp); @@ -550,7 +823,6 @@ /* support old dtbs that incorrectly describe IRQs */ pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); #endif - if (!pci_has_flag(PCI_PROBE_ONLY)) { pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -561,6 +833,7 @@ pci_bus_add_devices(bus); return 0; + } static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, @@ -574,16 +847,13 @@ busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); + cpu_addr = pp->cfg0_base; + cfg_size = pp->cfg0_size; + va_cfg_base = pp->va_cfg0_base; if (bus->parent->number == pp->root_bus_nr) { type = PCIE_ATU_TYPE_CFG0; - cpu_addr = pp->cfg0_base; - cfg_size = pp->cfg0_size; - va_cfg_base = pp->va_cfg0_base; } else { type = PCIE_ATU_TYPE_CFG1; - cpu_addr = pp->cfg1_base; - cfg_size = pp->cfg1_size; - va_cfg_base = pp->va_cfg1_base; } dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, @@ -608,16 +878,13 @@ busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); + cpu_addr = pp->cfg0_base; + cfg_size = pp->cfg0_size; + va_cfg_base = pp->va_cfg0_base; if (bus->parent->number == pp->root_bus_nr) { type = PCIE_ATU_TYPE_CFG0; - cpu_addr = pp->cfg0_base; - cfg_size = pp->cfg0_size; - va_cfg_base = pp->va_cfg0_base; } else { type = PCIE_ATU_TYPE_CFG1; - cpu_addr = pp->cfg1_base; - cfg_size = pp->cfg1_size; - va_cfg_base = pp->va_cfg1_base; } dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, @@ -658,46 +925,36 @@ int size, u32 *val) { struct pcie_port *pp = bus->sysdata; - int ret; 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) - 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); + if (bus->number == pp->root_bus_nr) + return dw_pcie_rd_own_conf(pp, where, size, val); - return ret; + if (pp->ops->rd_other_conf) + return pp->ops->rd_other_conf(pp, bus, devfn, where, size, val); + + return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val); } static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 val) { struct pcie_port *pp = bus->sysdata; - int ret; if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) return PCIBIOS_DEVICE_NOT_FOUND; - if (bus->number != pp->root_bus_nr) - 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); + if (bus->number == pp->root_bus_nr) + return dw_pcie_wr_own_conf(pp, where, size, val); - return ret; + if (pp->ops->wr_other_conf) + return pp->ops->wr_other_conf(pp, bus, devfn, where, size, val); + + return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val); } static struct pci_ops dw_pcie_ops = { @@ -708,8 +965,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp) { u32 val; - u32 membase; - u32 memlimit; /* set the number of lanes */ dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val); @@ -768,18 +1023,31 @@ val |= 0x00010100; dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS); - /* setup memory base, memory limit */ - membase = ((u32)pp->mem_base & 0xfff00000) >> 16; - memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000; - val = memlimit | membase; - dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE); - /* setup command register */ dw_pcie_readl_rc(pp, PCI_COMMAND, &val); val &= 0xffff0000; val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR; dw_pcie_writel_rc(pp, val, PCI_COMMAND); + + /* + * If the platform provides ->rd_other_conf, it means the platform + * uses its own address translation component rather than ATU, so + * we should not program the ATU here. + */ + if (!pp->ops->rd_other_conf) + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_MEM, pp->mem_base, + pp->mem_bus_addr, pp->mem_size); + + dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0); + + /* program correct class for RC */ + dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI); + + dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val); + val |= PORT_LOGIC_SPEED_CHANGE; + dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val); } MODULE_AUTHOR("Jingoo Han ");