From 192e945479a9c90eb7d6a3ff563084cb558ba31a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 Dec 2014 16:23:42 +0000 Subject: [PATCH] bcm53xx: PCIe: add link check again When there is no device connected to the controller we should not start the controller. This also changes between PCIe 1.0 and PCIe 2.0 speed based on the device. This code is based on code from the new Broadcom PCIe controller driver. Signed-off-by: Hauke Mehrtens SVN-Revision: 43748 --- ...2-bcma-add-new-PCIe2-driver-for-bcma.patch | 81 +++++++++++++------ ...2-bcma-add-new-PCIe2-driver-for-bcma.patch | 81 +++++++++++++------ 2 files changed, 112 insertions(+), 50 deletions(-) diff --git a/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch b/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch index dcdbb8f967..e9631335de 100644 --- a/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch +++ b/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch @@ -72,7 +72,7 @@ Signed-off-by: Hauke Mehrtens +obj-$(CONFIG_PCI_BCM5301X) += pci-host-bcm5301x.o --- /dev/null +++ b/drivers/pci/host/pci-host-bcm5301x.c -@@ -0,0 +1,428 @@ +@@ -0,0 +1,459 @@ +/* + * Northstar PCI-Express driver + * Only supports Root-Complex (RC) mode @@ -94,13 +94,16 @@ Signed-off-by: Hauke Mehrtens +#include +#include +#include -+#include +#include +#include -+#include + +#define SOC_PCIE_HDR_OFF 0x400 /* 256 bytes per function */ + ++#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC ++#define PCI_TARGET_LINK_SPEED_MASK 0xF ++#define PCI_TARGET_LINK_SPEED_GEN2 0x2 ++#define PCI_TARGET_LINK_SPEED_GEN1 0x1 ++ +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = pdev->sysdata; @@ -222,31 +225,59 @@ Signed-off-by: Hauke Mehrtens + * Check link status, return 0 if link is up in RC mode, + * otherwise return non-zero + */ -+static int bcma_pcie2_check_link(struct bcma_device *bdev, bool allow_gen2) ++static int bcma_pcie2_check_link(struct bcma_device *bdev, struct pci_sys_data *sys) +{ -+ u32 devfn = 0; + u32 tmp32; -+ u8 tmp8; -+ -+ tmp32 = bcma_pcie2_read_config(bdev, 0, devfn, 0xdc, 4); -+ tmp32 &= ~0xf; -+ if (allow_gen2) -+ tmp32 |= 2; -+ else { -+ /* force PCIE GEN1 */ -+ tmp32 |= 1; -+ } -+ bcma_pcie2_write_config(bdev, 0, devfn, 0xdc, 4, tmp32); -+ -+ /* See if the port is in EP mode, indicated by header type 00 */ -+ tmp8 = bcma_pcie2_read_config(bdev, 0, devfn, PCI_HEADER_TYPE, 1); -+ if (tmp8 != PCI_HEADER_TYPE_BRIDGE) { -+ dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n", -+ bdev->core_unit); -+ return -ENODEV; ++ u16 tmp16; ++ u16 pos; ++ u8 nlw; ++ /* ++ * Setup callback (bcma_pcie2_setup) is called in pcibios_init_hw before ++ * creating bus root, so we don't have it here yet. On the other hand ++ * we really want to use pci_bus_find_capability helper to check NLW. ++ * Let's fake simple pci_bus just to query for capabilities. ++ */ ++ struct pci_bus bus = { ++ .number = 0, ++ .ops = &bcma_pcie2_ops, ++ .sysdata = sys, ++ }; ++ ++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_LINK_STATUS); ++ dev_dbg(&bdev->dev, "link status: 0x%08x\n", tmp32); ++ ++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_STRAP_STATUS); ++ dev_dbg(&bdev->dev, "strap status: 0x%08x\n", tmp32); ++ ++ /* check link status to see if link is active */ ++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP); ++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA, &tmp16); ++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT; ++ ++ if (nlw == 0) { ++ /* try GEN 1 link speed */ ++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4); ++ if ((tmp32 & PCI_TARGET_LINK_SPEED_MASK) == ++ PCI_TARGET_LINK_SPEED_GEN2) { ++ tmp32 &= ~PCI_TARGET_LINK_SPEED_MASK; ++ tmp32 |= PCI_TARGET_LINK_SPEED_GEN1; ++ bcma_pcie2_write_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4, tmp32); ++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4); ++ msleep(100); ++ ++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP); ++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA, ++ &tmp16); ++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> ++ PCI_EXP_LNKSTA_NLW_SHIFT; ++ } + } + -+ return 0; ++ dev_info(&bdev->dev, "link: %s\n", nlw ? "UP" : "DOWN"); ++ return nlw ? 0 : -ENODEV; +} + +/* @@ -438,7 +469,7 @@ Signed-off-by: Hauke Mehrtens + * Skip inactive ports - + * will need to change this for hot-plugging + */ -+ ret = bcma_pcie2_check_link(bdev, true); ++ ret = bcma_pcie2_check_link(bdev, sys); + if (ret) + return ret; + diff --git a/target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch b/target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch index fc616d7cd3..1a8460490f 100644 --- a/target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch +++ b/target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch @@ -72,7 +72,7 @@ Signed-off-by: Hauke Mehrtens +obj-$(CONFIG_PCI_BCM5301X) += pci-host-bcm5301x.o --- /dev/null +++ b/drivers/pci/host/pci-host-bcm5301x.c -@@ -0,0 +1,428 @@ +@@ -0,0 +1,459 @@ +/* + * Northstar PCI-Express driver + * Only supports Root-Complex (RC) mode @@ -94,13 +94,16 @@ Signed-off-by: Hauke Mehrtens +#include +#include +#include -+#include +#include +#include -+#include + +#define SOC_PCIE_HDR_OFF 0x400 /* 256 bytes per function */ + ++#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC ++#define PCI_TARGET_LINK_SPEED_MASK 0xF ++#define PCI_TARGET_LINK_SPEED_GEN2 0x2 ++#define PCI_TARGET_LINK_SPEED_GEN1 0x1 ++ +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = pdev->sysdata; @@ -222,31 +225,59 @@ Signed-off-by: Hauke Mehrtens + * Check link status, return 0 if link is up in RC mode, + * otherwise return non-zero + */ -+static int bcma_pcie2_check_link(struct bcma_device *bdev, bool allow_gen2) ++static int bcma_pcie2_check_link(struct bcma_device *bdev, struct pci_sys_data *sys) +{ -+ u32 devfn = 0; + u32 tmp32; -+ u8 tmp8; -+ -+ tmp32 = bcma_pcie2_read_config(bdev, 0, devfn, 0xdc, 4); -+ tmp32 &= ~0xf; -+ if (allow_gen2) -+ tmp32 |= 2; -+ else { -+ /* force PCIE GEN1 */ -+ tmp32 |= 1; -+ } -+ bcma_pcie2_write_config(bdev, 0, devfn, 0xdc, 4, tmp32); -+ -+ /* See if the port is in EP mode, indicated by header type 00 */ -+ tmp8 = bcma_pcie2_read_config(bdev, 0, devfn, PCI_HEADER_TYPE, 1); -+ if (tmp8 != PCI_HEADER_TYPE_BRIDGE) { -+ dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n", -+ bdev->core_unit); -+ return -ENODEV; ++ u16 tmp16; ++ u16 pos; ++ u8 nlw; ++ /* ++ * Setup callback (bcma_pcie2_setup) is called in pcibios_init_hw before ++ * creating bus root, so we don't have it here yet. On the other hand ++ * we really want to use pci_bus_find_capability helper to check NLW. ++ * Let's fake simple pci_bus just to query for capabilities. ++ */ ++ struct pci_bus bus = { ++ .number = 0, ++ .ops = &bcma_pcie2_ops, ++ .sysdata = sys, ++ }; ++ ++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_LINK_STATUS); ++ dev_dbg(&bdev->dev, "link status: 0x%08x\n", tmp32); ++ ++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_STRAP_STATUS); ++ dev_dbg(&bdev->dev, "strap status: 0x%08x\n", tmp32); ++ ++ /* check link status to see if link is active */ ++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP); ++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA, &tmp16); ++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT; ++ ++ if (nlw == 0) { ++ /* try GEN 1 link speed */ ++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4); ++ if ((tmp32 & PCI_TARGET_LINK_SPEED_MASK) == ++ PCI_TARGET_LINK_SPEED_GEN2) { ++ tmp32 &= ~PCI_TARGET_LINK_SPEED_MASK; ++ tmp32 |= PCI_TARGET_LINK_SPEED_GEN1; ++ bcma_pcie2_write_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4, tmp32); ++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0, ++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4); ++ msleep(100); ++ ++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP); ++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA, ++ &tmp16); ++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> ++ PCI_EXP_LNKSTA_NLW_SHIFT; ++ } + } + -+ return 0; ++ dev_info(&bdev->dev, "link: %s\n", nlw ? "UP" : "DOWN"); ++ return nlw ? 0 : -ENODEV; +} + +/* @@ -438,7 +469,7 @@ Signed-off-by: Hauke Mehrtens + * Skip inactive ports - + * will need to change this for hot-plugging + */ -+ ret = bcma_pcie2_check_link(bdev, true); ++ ret = bcma_pcie2_check_link(bdev, sys); + if (ret) + return ret; + -- 2.30.2