From patchwork Sat May 31 14:27:58 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Noever X-Patchwork-Id: 354492 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id DE6031400FE for ; Sun, 1 Jun 2014 00:30:26 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933149AbaEaO3L (ORCPT ); Sat, 31 May 2014 10:29:11 -0400 Received: from mail-qa0-f50.google.com ([209.85.216.50]:54108 "EHLO mail-qa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933095AbaEaO3I (ORCPT ); Sat, 31 May 2014 10:29:08 -0400 Received: by mail-qa0-f50.google.com with SMTP id j15so411164qaq.23 for ; Sat, 31 May 2014 07:29:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vuAWcmGY8JnhoVU+Q+A7FTYheRMqw4mBuLbzTgY/fbE=; b=KDBWaFffTAAKZXr9IYQsTyhQxS9hEfDAX+LiZ3epWKVUzuKNdOwd9BHW9WfqMTCiEI 1Dl71i4BXqDTUBSwTLRieYiFnxiFWURIlUpE7nUbSSR+1KiX5rV/8s2eb2rTVkoPmuSZ EZjpE7EpA43r2r4yoE6FtC3FecmtS/V2EQeOZZVw1tS3oAwexuF5lznkSgqe2IizC7s9 DFp2fAbZMBH8Mtth9jetkhw/iCU4tgMdsIyxj3Hii17j9Ia3+gsaicKDwrKMdGgQ2V+N GsWw7vPmKMwa7J/nVl6bAz2aDH74i/nBdt+Q6IAzFbkH1VNpraHGO5JuEeWwVYbCIe/f iJbw== X-Received: by 10.140.107.67 with SMTP id g61mr29847444qgf.100.1401546547159; Sat, 31 May 2014 07:29:07 -0700 (PDT) Received: from linuxbook.fritz.box (HSI-KBW-109-193-140-057.hsi7.kabel-badenwuerttemberg.de. [109.193.140.57]) by mx.google.com with ESMTPSA id q7sm11542251qad.12.2014.05.31.07.29.05 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 31 May 2014 07:29:06 -0700 (PDT) From: Andreas Noever To: linux-kernel@vger.kernel.org, Matthew Garrett , Greg KH , Bjorn Helgaas , linux-pci@vger.kernel.org Cc: Andreas Noever Subject: [PATCH v4 13/15] PCI: Suspend/resume quirks for Apple thunderbolt Date: Sat, 31 May 2014 16:27:58 +0200 Message-Id: <1401546480-2071-14-git-send-email-andreas.noever@gmail.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1401546480-2071-1-git-send-email-andreas.noever@gmail.com> References: <1401546480-2071-1-git-send-email-andreas.noever@gmail.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Add two quirks to support thunderbolt suspend/resume on Apple systems. We need to perform two different actions during suspend and resume: The whole controller has to be powered down before suspend. If this is not done then the native host interface device will be gone after resume if a thunderbolt device was plugged in before suspending. The controller represents itself as multiple PCI devices/bridges. To power it down we hook into the upstream bridge of the controller and call the magic ACPI methods. Power will be restored automatically during resume (by the firmware presumably). During resume we have to wait for the native host interface to reestablish all pci tunnels. Since there is no parent-child relationship between the NHI and the bridges we have to explicitly wait for them using device_pm_wait_for_dev. We do this in the resume_noirq phase of the downstream bridges of the controller (which lead into the thunderbolt tunnels). Signed-off-by: Andreas Noever Acked-by: Bjorn Helgaas --- drivers/pci/quirks.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index af2eba1..c9d6b90 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2992,6 +2992,128 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, 0x0030, DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ quirk_broken_intx_masking); +#ifdef CONFIG_ACPI +/* Apple systems with a Cactus Ridge Thunderbolt controller. */ +static struct dmi_system_id apple_thunderbolt_whitelist[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir5"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir6"), + }, + }, + { } +}; + +/* + * Apple: Shutdown Cactus Ridge Thunderbolt controller. + * + * On Apple hardware the Cactus Ridge Thunderbolt controller needs to be + * shutdown before suspend. Otherwise the native host interface (NHI) will not + * be present after resume if a device was plugged in before suspend. + * + * The thunderbolt controller consists of a pcie switch with downstream + * bridges leading to the NHI and to the tunnel pci bridges. + * + * This quirk cuts power to the whole chip. Therefore we have to apply it + * during suspend_noirq of the upstream bridge. + * + * Power is automagically restored before resume. No action is needed. + */ +static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev) +{ + acpi_handle bridge, SXIO, SXFP, SXLV; + + if (!dmi_check_system(apple_thunderbolt_whitelist)) + return; + if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) + return; + bridge = ACPI_HANDLE(&dev->dev); + if (!bridge) + return; + /* + * TB bridges in external devices might have the same device id as those + * on the host, but they will not have the associated ACPI methods. This + * implicitly checks that we are at the right bridge. + */ + if (ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXIO", &SXIO)) + || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXFP", &SXFP)) + || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXLV", &SXLV))) + return; + dev_info(&dev->dev, "quirk: cutting power to thunderbolt controller...\n"); + + /* magic sequence */ + acpi_execute_simple_method(SXIO, NULL, 1); + acpi_execute_simple_method(SXFP, NULL, 0); + msleep(300); + acpi_execute_simple_method(SXLV, NULL, 0); + acpi_execute_simple_method(SXIO, NULL, 0); + acpi_execute_simple_method(SXLV, NULL, 0); +} +DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL, 0x1547, + quirk_apple_poweroff_thunderbolt); + +/* + * Apple: Wait for the thunderbolt controller to reestablish pci tunnels. + * + * During suspend the thunderbolt controller is reset and all pci + * tunnels are lost. The NHI driver will try to reestablish all tunnels + * during resume. We have to manually wait for the NHI since there is + * no parent child relationship between the NHI and the tunneled + * bridges. + */ +static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev) +{ + struct pci_dev *sibling = NULL; + struct pci_dev *nhi = NULL; + + if (!dmi_check_system(apple_thunderbolt_whitelist)) + return; + if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM) + return; + /* + * Find the NHI and confirm that we are a bridge on the tb host + * controller and not on a tb endpoint. + */ + sibling = pci_get_slot(dev->bus, 0x0); + if (sibling == dev) + goto out; /* we are the downstream bridge to the NHI */ + if (!sibling || !sibling->subordinate) + goto out; + nhi = pci_get_slot(sibling->subordinate, 0x0); + if (!nhi) + goto out; + if (nhi->vendor != PCI_VENDOR_ID_INTEL || nhi->device != 0x1547 + || nhi->subsystem_vendor != 0x2222 + || nhi->subsystem_device != 0x1111) + goto out; + dev_info(&dev->dev, "quirk: wating for thunderbolt to reestablish pci tunnels...\n"); + device_pm_wait_for_dev(&dev->dev, &nhi->dev); +out: + pci_dev_put(nhi); + pci_dev_put(sibling); +} +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x1547, + quirk_apple_wait_for_thunderbolt); +#endif + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) {