On Monday 24 March 2014 20:35:26 Murali Karicheri wrote:
+It seems you have a distinct register set for the PHY that you are
+int k2_pcie_platform_setup(struct platform_device *pdev)
+{
+ struct resource *phy_base_r, *devstat_r;
+ void __iomem *phy_base, *devstat;
+ u32 val;
+ int i;
+
+ devstat_r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "reg_devcfg");
+ if (!devstat_r)
+ return -ENODEV;
driving here. Why not make this part generic PHY API driver?
Ok. I think I could use usleep_range() API here+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)You are blocking the CPU for up to one second here, which is really
+{
+ struct pcie_port *pp = &ks_pcie->pp;
+ int count = 0;
+
+ dw_pcie_setup_rc(pp);
+
+ /* check if the link is up or not */
+ while (!dw_pcie_link_up(pp)) {
+ mdelay(100);
+ count++;
+ if (count == 10)
+ return -EINVAL;
+ }
+ return 0;
+}
nasty. Please find a way to move the code into a context where you
can sleep and use msleep() instead, or better use an interrupt if the
hardware supports that and use wait_for_completion().
Yes. Can be moved to a separate file, dw-msi-v3.65.c ??+Did I understand this right that the MSI implementation can be used
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+ u32 offset = irq - ks_pcie->msi_host_irqs[0], pending, vector;
+ struct pcie_port *pp = &ks_pcie->pp;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ int src, virq;
by any dw-pcie hardware of the same version? If so, it would be good
to move it into an extra file so it can be shared with the next host
driver that uses this version.
+/**Why do you need to set this up from the kernel? Please move the
+ * ks_pcie_set_outbound_trans() - Set PHYADDR <-> BUSADDR
+ * mapping for outbound
+ */
+static void ks_pcie_set_outbound_trans(struct keystone_pcie *ks_pcie)
+static void ks_pcie_set_inbound_trans(struct pcie_port *pp)
translation window setup into the boot loader if you can.
+static struct hw_pci keystone_pcie_hw = {This can just be a local variable in the probe function.
+ .nr_controllers = 1,
+ .setup = dw_pcie_setup,
+ .scan = ks_pcie_scan_bus,
+ .swizzle = pci_common_swizzle,
+ .add_bus = dw_pcie_add_bus,
+ .map_irq = ks_pcie_map_irq,
+};
+Can you use the generic irqchip code here?
+static int ks_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+ dev_info(pp->dev, "ks_pcie_map_irq: pin %d\n", pin);
+
+ if (!pin || pin > ks_pcie->num_legacy_host_irqs) {
+ dev_err(pp->dev, "pci irq pin out of range\n");
+ return -1;
+ }
+
+ /* pin has values from 1-4 */
+ return (ks_pcie->virqs[pin - 1] >= 0) ?
+ ks_pcie->virqs[pin - 1] : -1;
+}
+
+
+static void ack_irq(struct irq_data *d)
+{
+}
+
+static void mask_irq(struct irq_data *d)
+{
+}
+
+static void unmask_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip ks_pcie_legacy_irq_chip = {
+ .name = "PCIe-LEGACY-IRQ",
+ .irq_ack = ack_irq,
+ .irq_mask = mask_irq,
+ .irq_unmask = unmask_irq,
+};
+ /*I have no idea how this would work with the standard interrupt-map property,
+ * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
+ * In dt from index 0 to 3
+ */
+ for (i = 0; i < MAX_LEGACY_HOST_IRQS; i++) {
+ ks_pcie->legacy_host_irqs[i] = irq_of_parse_and_map(np, i);
+ if (ks_pcie->legacy_host_irqs[i] < 0)
+ break;
+ ks_pcie->num_legacy_host_irqs++;
+ }
+
+ if (ks_pcie->num_legacy_host_irqs) {
+ ks_pcie->legacy_irqd = irq_domain_add_linear(np,
+ ks_pcie->num_legacy_host_irqs,
+ &irq_domain_simple_ops, NULL);
+
+ if (!ks_pcie->legacy_irqd) {
+ dev_err(dev,
+ "Failed to add irq domain for legacy irqs\n");
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+ ks_pcie->virqs[i] =
+ irq_create_mapping(ks_pcie->legacy_irqd, i);
+ irq_set_chip_and_handler(ks_pcie->virqs[i],
+ &ks_pcie_legacy_irq_chip, handle_level_irq);
+ irq_set_chip_data(ks_pcie->virqs[i], ks_pcie);
+ set_irq_flags(ks_pcie->virqs[i], IRQF_VALID);
+
+ if (ks_pcie->legacy_host_irqs[i] >= 0) {
+ irq_set_handler_data(ks_pcie->legacy_host_irqs[i],
+ ks_pcie);
+ irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+ ks_pcie_legacy_irq_handler);
+ }
+ set_irq_flags(ks_pcie->legacy_host_irqs[i], IRQF_VALID);
+ }
since the legacy interrupt host is now the same device as the pci host.
Maybe it's better to move the legacy irqchip handling entirely out of
the driver and use a separate device node for the registers so it can
come with its own #interrupt-cells, and then refer to this irqchip from
the interrupt-map.
+ ks_pcie->clk = devm_clk_get(&pdev->dev, "pcie");Could you move the clock handling into the generic dw-pcie code?
+ if (IS_ERR(ks_pcie->clk)) {
+ dev_err(&pdev->dev, "Failed to get pcie rc clock\n");
+ return PTR_ERR(ks_pcie->clk);
+ }
+ ret = clk_prepare_enable(ks_pcie->clk);
+ if (ret)
+ return ret;
+Why subsys_initcall?
+/* Keystone PCIe driver does not allow module unload */
+static int __init ks_pcie_init(void)
+{
+ return platform_driver_probe(&ks_pcie_driver, ks_pcie_probe);
+}
+subsys_initcall(ks_pcie_init);
We should probably try to fix unloading soon.
Will investigate.
diff --git a/drivers/pci/host/pcie-ks-pdata.h b/drivers/pci/host/pcie-ks-pdata.hThis should all go away once you have a proper PHY driver.
new file mode 100644
index 0000000..a7626de
--- /dev/null
+++ b/drivers/pci/host/pcie-ks-pdata.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ * http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@xxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* platform specific setup for k2 pcie */
+int k2_pcie_platform_setup(struct platform_device *pdev);
+
+/* keystone pcie pdata configurations */
+struct keystone_pcie_pdata {
+ int (*setup)(struct platform_device *pdev);
+};
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.cYou can't do this:
index 3a02717..7c3f777 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3461,3 +3461,15 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
return -ENOTTY;
}
+
+#ifdef CONFIG_PCIE_KEYSTONE
+/*
+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
+ * Force this configuration for all EP including bridges.
+ */
+static void quirk_limit_readrequest(struct pci_dev *dev)
+{
+ pcie_set_readrq(dev, 256);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
+#endif /* CONFIG_TI_KEYSTONE_PCIE */
A quirk for a specific hardware must not be enabled by compile-time options.
You have to find a different way to do this.
Arnd