On Friday, July 05, 2013 7:46 PM, Arnd Bergmann wrote: > On Friday 05 July 2013, Jingoo Han wrote: > > > --- /dev/null > > +++ b/drivers/pci/host/pcie-exynos.c > > > + > > +/* PCIe ELBI registers */ > > +#define PCIE_IRQ_PULSE 0x000 > > +#define IRQ_INTA_ASSERT (0x1 << 0) > > +#define IRQ_INTB_ASSERT (0x1 << 2) > > +#define IRQ_INTC_ASSERT (0x1 << 4) > > +#define IRQ_INTD_ASSERT (0x1 << 6) > > +#define PCIE_IRQ_LEVEL 0x004 > > +#define PCIE_IRQ_SPECIAL 0x008 > > +#define PCIE_IRQ_EN_PULSE 0x00c > > +#define PCIE_IRQ_EN_LEVEL 0x010 > > +#define PCIE_IRQ_EN_SPECIAL 0x014 > > +#define PCIE_PWR_RESET 0x018 > > +#define PCIE_CORE_RESET 0x01c > > +#define PCIE_CORE_RESET_ENABLE (0x1 << 0) > > +#define PCIE_STICKY_RESET 0x020 > > +#define PCIE_NONSTICKY_RESET 0x024 > > +#define PCIE_APP_INIT_RESET 0x028 > > +#define PCIE_APP_LTSSM_ENABLE 0x02c > > +#define PCIE_ELBI_RDLH_LINKUP 0x064 > > +#define PCIE_ELBI_LTSSM_ENABLE 0x1 > > +#define PCIE_ELBI_SLV_AWMISC 0x11c > > +#define PCIE_ELBI_SLV_ARMISC 0x120 > > +#define PCIE_ELBI_SLV_DBI_ENABLE (0x1 << 21) > > + > > +/* PCIe Purple registers */ > > +#define PCIE_PHY_GLOBAL_RESET 0x000 > > +#define PCIE_PHY_COMMON_RESET 0x004 > > +#define PCIE_PHY_CMN_REG 0x008 > > +#define PCIE_PHY_MAC_RESET 0x00c > > +#define PCIE_PHY_PLL_LOCKED 0x010 > > +#define PCIE_PHY_TRSVREG_RESET 0x020 > > +#define PCIE_PHY_TRSV_RESET 0x024 > > + > > +/* PCIe PHY registers */ > > +#define PCIE_PHY_IMPEDANCE 0x004 > > +#define PCIE_PHY_PLL_DIV_0 0x008 > > +#define PCIE_PHY_PLL_BIAS 0x00c > > +#define PCIE_PHY_DCC_FEEDBACK 0x014 > > +#define PCIE_PHY_PLL_DIV_1 0x05c > > +#define PCIE_PHY_TRSV0_EMP_LVL 0x084 > > +#define PCIE_PHY_TRSV0_DRV_LVL 0x088 > > +#define PCIE_PHY_TRSV0_RXCDR 0x0ac > > +#define PCIE_PHY_TRSV0_LVCC 0x0dc > > +#define PCIE_PHY_TRSV1_EMP_LVL 0x144 > > +#define PCIE_PHY_TRSV1_RXCDR 0x16c > > +#define PCIE_PHY_TRSV1_LVCC 0x19c > > +#define PCIE_PHY_TRSV2_EMP_LVL 0x204 > > +#define PCIE_PHY_TRSV2_RXCDR 0x22c > > +#define PCIE_PHY_TRSV2_LVCC 0x25c > > +#define PCIE_PHY_TRSV3_EMP_LVL 0x2c4 > > +#define PCIE_PHY_TRSV3_RXCDR 0x2ec > > +#define PCIE_PHY_TRSV3_LVCC 0x31c > > Are you sure these are all exynos specific? Maybe they are licensed > from someone else? Samsung specific. I asked our hardware engineer, and he confirmed it. > > > + > > + pp->dbi_base = devm_ioremap(&pdev->dev, pp->cfg.start, > > + resource_size(&pp->cfg)); > > + if (!pp->dbi_base) { > > + dev_err(&pdev->dev, "error with ioremap\n"); > > + return -ENOMEM; > > + } > > + > > + pp->root_bus_nr = -1; > > + pp->ops = &exynos_pcie_host_ops; > > + > > + spin_lock_init(&pp->conf_lock); > > + dw_pcie_host_init(pp); > > + pp->va_cfg0_base = devm_ioremap(&pdev->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_cfg1_base = devm_ioremap(&pdev->dev, pp->cfg1_base, > > + pp->config.cfg1_size); > > + if (!pp->va_cfg1_base) { > > + dev_err(pp->dev, "error with ioremap\n"); > > + return -ENOMEM; > > + } > > I think the configuration space handling should go into the > dw_pcie_host_init function, as that part would be needed by all drivers. OK. I will move it to dw_pcie_host_init(). > > > +static int __init exynos_pcie_probe(struct platform_device *pdev) > > +{ > > + struct pcie_port *pp; > > + struct device_node *np = pdev->dev.of_node; > > + struct of_pci_range range; > > + struct of_pci_range_parser parser; > > + int ret; > > + > > + pp = devm_kzalloc(&pdev->dev, sizeof(*pp), GFP_KERNEL); > > + if (!pp) { > > + dev_err(&pdev->dev, "no memory for pcie port\n"); > > + return -ENOMEM; > > + } > > + > > + pp->dev = &pdev->dev; > > + > > + if (of_pci_range_parser_init(&parser, np)) { > > + dev_err(&pdev->dev, "missing ranges property\n"); > > + return -EINVAL; > > + } > > + > > + /* Get the I/O and memory ranges from DT */ > > + for_each_of_pci_range(&parser, &range) { > > + unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; > > + if (restype == IORESOURCE_IO) { > > + of_pci_range_to_resource(&range, np, &pp->io); > > + pp->io.name = "I/O"; > > + pp->io.start = max_t(resource_size_t, > > + PCIBIOS_MIN_IO, > > + range.pci_addr + global_io_offset); > > + 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; > > + } > > + 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; > > + } > > + 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; > > + } > > + } > > Same for these: it would be better to split up the probe function here > and move all of the above into the common code. OK. I will move it to dw_pcie_host_init(). > > > + pp->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); > > I assume the reset logic would need to remain exynos specific > > > + pp->clk = devm_clk_get(&pdev->dev, "pcie"); > > + if (IS_ERR(pp->clk)) { > > + dev_err(&pdev->dev, "Failed to get pcie rc clock\n"); > > + return PTR_ERR(pp->clk); > > + } > > + ret = clk_prepare_enable(pp->clk); > > + if (ret) > > + return ret; > > + > > + pp->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus"); > > + if (IS_ERR(pp->bus_clk)) { > > + dev_err(&pdev->dev, "Failed to get pcie bus clock\n"); > > + ret = PTR_ERR(pp->bus_clk); > > + goto fail_clk; > > + } > > + ret = clk_prepare_enable(pp->bus_clk); > > + if (ret) > > + goto fail_clk; > > For the clocks, I think we can keep them in the common code, but > make them optional, i.e. do not fail the probe function if the clocks > don't exist, i.e. you get -ENOENT from devm_clk_get. We should however > still fail here if devm_clk_get returns a different error. > > I also noticed an existing bug in your code here: if the clock controller > is not yet initialized, devm_clk_get() will return -EPROBE_DEFER, > which is broken in combination with platform_driver_probe. In order > to fix that, just change the code to use platform_driver_register > so it has the option to retry the probe after the clock controller > is initialized. > That should be a separate patch. If I should do it, I will send a separate patch. > > > +static int exynos_pcie_abort(unsigned long addr, unsigned int fsr, > > + struct pt_regs *regs) > > +{ > > + unsigned long pc = instruction_pointer(regs); > > + unsigned long instr = *(unsigned long *)pc; > > + > > + WARN_ONCE(1, "pcie abort\n"); > > + > > + /* > > + * If the instruction being executed was a read, > > + * make it look like it read all-ones. > > + */ > > + if ((instr & 0x0c100000) == 0x04100000) { > > + int reg = (instr >> 12) & 15; > > + unsigned long val; > > + > > + if (instr & 0x00400000) > > + val = 255; > > + else > > + val = -1; > > + > > + regs->uregs[reg] = val; > > + regs->ARM_pc += 4; > > + return 0; > > + } > > + > > + if ((instr & 0x0e100090) == 0x00100090) { > > + int reg = (instr >> 12) & 15; > > + > > + regs->uregs[reg] = -1; > > + regs->ARM_pc += 4; > > + return 0; > > + } > > + > > + return 1; > > +} > > Another observation that is only partially related: the abort handler logic > is not specific to either exynos nor synopsys. However it is specific > to ARM and should not be part of a driver that is potentially architecture > independent. I would recommend moving this to a separate file > "arm-pci-abort.c" or something like that. I notice that a lot of the other > ARM PCI implementations have the exact same code but also need to reset > the abort in the bridge. Can you confirm that a) you don't need to tell > the root port about the abort and b) the abort handler is actually required > for exynos? How often do you run into this? There is no special reason to add it. I just referenced other ARM PCI drivers. Also, I have never seen calling this abort function. Then, I will remove it. Thank you for your opinion. :) Your comment is very helpful. Best regards, Jingoo Han -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html