]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
thunderbolt: Support 1st gen Light Ridge controller
authorLukas Wunner <lukas@wunner.de>
Sun, 20 Mar 2016 12:57:20 +0000 (13:57 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 8 Apr 2016 16:13:40 +0000 (11:13 -0500)
Add support for the 1st gen Light Ridge controller, which is built into
these systems:

  iMac12,1       2011  21.5"
  iMac12,2       2011  27"
  Macmini5,1     2011  i5 2.3 GHz
  Macmini5,2     2011  i5 2.5 GHz
  Macmini5,3     2011  i7 2.0 GHz
  MacBookPro8,1  2011  13"
  MacBookPro8,2  2011  15"
  MacBookPro8,3  2011  17"
  MacBookPro9,1  2012  15"
  MacBookPro9,2  2012  13"

Light Ridge (CV82524) was the very first copper Thunderbolt controller,
introduced 2010 alongside its fiber-optic cousin Light Peak (CVL2510).
Consequently the chip suffers from some teething troubles:

  - MSI is broken for hotplug signaling on the downstream bridges: The chip
    just never sends an interrupt.  It requests 32 MSIs for each of its six
    bridges and the pcieport driver only allocates one per bridge.  However
    I've verified that even if 32 MSIs are allocated there's no interrupt
    on hotplug.  The only option is thus to disable MSI, which is also what
    OS X does.  Apparently all Thunderbolt chips up to revision 1 of Cactus
    Ridge 4C are plagued by this issue so quirk those as well.

  - The chip supports a maximum hop_count of 32, unlike its successors
    which support only 12.  Fixup ring_interrupt_active() to cope with
    values >= 32.

  - Another peculiarity is that the chip supports a maximum of 13 ports
    whereas its successors support 12.  However the additional port (#5)
    seems to be unusable as reading its TB_CFG_PORT config space results in
    TB_CFG_ERROR_INVALID_CONFIG_SPACE.  Add a quirk to mark the port
    disabled on the root switch, assuming that's necessary on all Macs
    using this chip.

Tested-by: Lukas Wunner <lukas@wunner.de> [MacBookPro9,1]
Tested-by: William Brown <william@blackhats.net.au> [MacBookPro8,2]
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Andreas Noever <andreas.noever@gmail.com>
drivers/pci/quirks.c
drivers/thunderbolt/eeprom.c
drivers/thunderbolt/nhi.c
drivers/thunderbolt/switch.c

index b584ddf83555cb84d9d0f99e1db128d5323b199e..b1ff270622dd84a4b6ce2456ddc93ed9ac306152 100644 (file)
@@ -3185,6 +3185,29 @@ static void quirk_no_pm_reset(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
                               PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset);
 
+/*
+ * Thunderbolt controllers with broken MSI hotplug signaling:
+ * Entire 1st generation (Light Ridge, Eagle Ridge, Light Peak) and part
+ * of the 2nd generation (Cactus Ridge 4C up to revision 1, Port Ridge).
+ */
+static void quirk_thunderbolt_hotplug_msi(struct pci_dev *pdev)
+{
+       if (pdev->is_hotplug_bridge &&
+           (pdev->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C ||
+            pdev->revision <= 1))
+               pdev->no_msi = 1;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EAGLE_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LIGHT_PEAK,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
+                       quirk_thunderbolt_hotplug_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE,
+                       quirk_thunderbolt_hotplug_msi);
+
 #ifdef CONFIG_ACPI
 /*
  * Apple: Shutdown Cactus Ridge Thunderbolt controller.
@@ -3267,7 +3290,8 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
        if (!nhi)
                goto out;
        if (nhi->vendor != PCI_VENDOR_ID_INTEL
-                   || (nhi->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
+                   || (nhi->device != PCI_DEVICE_ID_INTEL_LIGHT_RIDGE &&
+                       nhi->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
                        nhi->device != PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI)
                    || nhi->subsystem_vendor != 0x2222
                    || nhi->subsystem_device != 0x1111)
@@ -3278,6 +3302,9 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
        pci_dev_put(nhi);
        pci_dev_put(sibling);
 }
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
+                              quirk_apple_wait_for_thunderbolt);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
                               PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
                               quirk_apple_wait_for_thunderbolt);
index 47e56e861d617842f61dff0022004b296bdaeb66..0c052e25c5bc257f7e3d99b830bc208f1e7ddb8a 100644 (file)
@@ -388,6 +388,11 @@ int tb_drom_read(struct tb_switch *sw)
                sw->ports[4].link_nr = 1;
                sw->ports[3].dual_link_port = &sw->ports[4];
                sw->ports[4].dual_link_port = &sw->ports[3];
+
+               /* Port 5 is inaccessible on this gen 1 controller */
+               if (sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE)
+                       sw->ports[5].disabled = true;
+
                return 0;
        }
 
index 36be23babb89a774720b69a56ea0554e78615516..9c15344b657acebb240e8555af47e572314acd5c 100644 (file)
@@ -37,7 +37,8 @@ static int ring_interrupt_index(struct tb_ring *ring)
  */
 static void ring_interrupt_active(struct tb_ring *ring, bool active)
 {
-       int reg = REG_RING_INTERRUPT_BASE + ring_interrupt_index(ring) / 32;
+       int reg = REG_RING_INTERRUPT_BASE +
+                 ring_interrupt_index(ring) / 32 * 4;
        int bit = ring_interrupt_index(ring) & 31;
        int mask = 1 << bit;
        u32 old, new;
@@ -564,7 +565,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* cannot fail - table is allocated bin pcim_iomap_regions */
        nhi->iobase = pcim_iomap_table(pdev)[0];
        nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff;
-       if (nhi->hop_count != 12)
+       if (nhi->hop_count != 12 && nhi->hop_count != 32)
                dev_warn(&pdev->dev, "unexpected hop count: %d\n",
                         nhi->hop_count);
        INIT_WORK(&nhi->interrupt_work, nhi_interrupt_work);
@@ -635,6 +636,12 @@ static struct pci_device_id nhi_ids[] = {
         * We have to specify class, the TB bridges use the same device and
         * vendor (sub)id on gen 1 and gen 2 controllers.
         */
+       {
+               .class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
+               .vendor = PCI_VENDOR_ID_INTEL,
+               .device = PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
+               .subvendor = 0x2222, .subdevice = 0x1111,
+       },
        {
                .class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
                .vendor = PCI_VENDOR_ID_INTEL,
index c6270f0bd5c5677a14e2ab69a8306c226122e8bc..1e116f53d6dddb254c465ebd5362d2c6162066a1 100644 (file)
@@ -370,7 +370,8 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
                tb_sw_warn(sw, "unknown switch vendor id %#x\n",
                           sw->config.vendor_id);
 
-       if (sw->config.device_id != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
+       if (sw->config.device_id != PCI_DEVICE_ID_INTEL_LIGHT_RIDGE &&
+           sw->config.device_id != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C &&
            sw->config.device_id != PCI_DEVICE_ID_INTEL_PORT_RIDGE)
                tb_sw_warn(sw, "unsupported switch device id %#x\n",
                           sw->config.device_id);