bcm53xx: PCIe: add link check again
authorHauke Mehrtens <hauke@hauke-m.de>
Thu, 18 Dec 2014 16:23:42 +0000 (16:23 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 18 Dec 2014 16:23:42 +0000 (16:23 +0000)
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 <hauke@hauke-m.de>
SVN-Revision: 43748

target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch

index dcdbb8f967345614f6d3b40b230be8a626580901..e9631335deaac654ac3e10e7053450b843d88200 100644 (file)
@@ -72,7 +72,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +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 <hauke@hauke-m.de>
 +#include <linux/pci.h>
 +#include <linux/io.h>
 +#include <linux/ioport.h>
-+#include <linux/interrupt.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/bcma/bcma_driver_pcie2.h>
-+#include <linux/of_irq.h>
 +
 +#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 <hauke@hauke-m.de>
 + * 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 <hauke@hauke-m.de>
 +       * 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;
 +
index fc616d7cd348bb0769f2b81383e38d799f7b6e0a..1a8460490f9fab902b4e48addf24e0655355ef1f 100644 (file)
@@ -72,7 +72,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +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 <hauke@hauke-m.de>
 +#include <linux/pci.h>
 +#include <linux/io.h>
 +#include <linux/ioport.h>
-+#include <linux/interrupt.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/bcma/bcma_driver_pcie2.h>
-+#include <linux/of_irq.h>
 +
 +#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 <hauke@hauke-m.de>
 + * 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 <hauke@hauke-m.de>
 +       * 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;
 +