Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions drivers/pci/controller/pcie-apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -5711,6 +5711,22 @@ static void apple_pcie_stop_for_sleep(struct device *dev)

static void apple_pcie_neo_save_functions(struct apple_pcie *pcie);

/* Whether Linux trained the port above pdev itself (cold train), rather than adopting it */
static bool apple_pcie_below_kernel_trained_port(struct pci_dev *pdev)
{
struct pci_config_window *cfg = pdev->sysdata;
struct apple_pcie *pcie = apple_pcie_lookup(cfg->parent);
struct pci_dev *rp = pcie_find_root_port(pdev);
struct apple_pcie_port *port;

if (!rp)
return false;
list_for_each_entry(port, &pcie->ports, entry)
if (port->idx == PCI_SLOT(rp->devfn))
return !!port->pwren;
return false;
}

/*
* The J716c radio drivers save PCI state without entering D3. The PCI core
* keeps the root port in D0 as well. Its host and DART have no switchable
Expand All @@ -5725,6 +5741,16 @@ static int apple_pcie_check_d0(struct pci_dev *pdev, void *data)
int *error = data;
u16 value;

/*
* Below a port the boot loader trained (the N1's), every device stays
* in D0. Below a port Linux trained itself (the K116s SD reader's), the
* PCI core restores what it suspends to D3hot, so only the devices that
* asked to stay awake need to remain in D0.
*/
if (!device_awake_path(&pdev->dev) &&
apple_pcie_below_kernel_trained_port(pdev))
return 0;

if (pci_read_config_word(pdev, PCI_VENDOR_ID, &value) ||
value != pdev->vendor) {
*error = -ENODEV;
Expand All @@ -5744,9 +5770,14 @@ static int apple_pcie_check_adopted_s2idle(struct apple_pcie *pcie)
struct apple_pcie_port *port;
int error = 0;

/* Other adopted platforms and deeper sleep remain unqualified. */
/*
* Qualified on the J716c, the K114c and the K116s. The K116s is the
* J716c's OLED sibling: the same T6050 host, the N1 on port 0. Other
* adopted platforms and deeper sleep remain unqualified.
*/
if (!(of_machine_is_compatible("apple,j716c") ||
of_machine_is_compatible("apple,k114c")) || !pm_suspend_no_platform())
of_machine_is_compatible("apple,k114c") ||
of_machine_is_compatible("apple,k116s")) || !pm_suspend_no_platform())
return -EBUSY;

if (!(readl(pcie->base + CORE_RC_CTL) & CORE_RC_CTL_RUN) ||
Expand Down
Loading