Skip to content
Open
Show file tree
Hide file tree
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
54 changes: 1 addition & 53 deletions drivers/pci/controller/dwc/pcie-designware-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,65 +443,13 @@ static ssize_t counter_value_read(struct file *file, char __user *buf,
return simple_read_from_buffer(buf, count, ppos, debugfs_buf, pos);
}

static const char *ltssm_status_string(enum dw_pcie_ltssm ltssm)
{
const char *str;

switch (ltssm) {
#define DW_PCIE_LTSSM_NAME(n) case n: str = #n; break
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_QUIET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_ACT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_ACTIVE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_COMPLIANCE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_CONFIG);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_PRE_DETECT_QUIET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_WAIT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_START);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_ACEPT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_WAI);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_ACEPT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_COMPLETE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_LOCK);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_SPEED);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_RCVRCFG);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0S);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L123_SEND_EIDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_WAKE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ACTIVE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT_TIMEOUT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ0);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ1);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ2);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ3);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_1);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_2);
default:
str = "DW_PCIE_LTSSM_UNKNOWN";
break;
}

return str + strlen("DW_PCIE_LTSSM_");
}

static int ltssm_status_show(struct seq_file *s, void *v)
{
struct dw_pcie *pci = s->private;
enum dw_pcie_ltssm val;

val = dw_pcie_get_ltssm(pci);
seq_printf(s, "%s (0x%02x)\n", ltssm_status_string(val), val);
seq_printf(s, "%s (0x%02x)\n", dw_pcie_ltssm_status_string(val), val);

return 0;
}
Expand Down
35 changes: 27 additions & 8 deletions drivers/pci/controller/dwc/pcie-designware-host.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>

#include "../pci-host-common.h"
#include "../../pci.h"
#include "pcie-designware.h"

Expand Down Expand Up @@ -664,8 +666,13 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
goto err_remove_edma;
}

/* Ignore errors, the link may come up later */
dw_pcie_wait_for_link(pci);
/*
* Only fail on timeout error. Other errors indicate the device may
* become available later, so continue without failing.
*/
ret = dw_pcie_wait_for_link(pci);
if (ret == -ETIMEDOUT)
goto err_stop_link;

ret = pci_host_probe(bridge);
if (ret)
Expand Down Expand Up @@ -1158,13 +1165,14 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)

int dw_pcie_suspend_noirq(struct dw_pcie *pci)
{
bool pme_capable = false;
int ret = 0;
u32 val;

if (!dw_pcie_link_up(pci))
goto stop_link;

if (!pci_host_common_can_enter_d3cold(pci->pp.bridge))
if (!pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable))
return 0;

pci->pp.skip_pwrctrl_off = true;
Expand Down Expand Up @@ -1206,6 +1214,7 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
udelay(1);

stop_link:
pci->pp.skip_pwrctrl_off = pme_capable;
dw_pcie_stop_link(pci);
if (pci->pp.ops->deinit)
pci->pp.ops->deinit(&pci->pp);
Expand All @@ -1223,9 +1232,6 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
if (!pci->suspended)
return 0;

pci->suspended = false;
pci->pp.skip_pwrctrl_off = false;

if (pci->pp.ops->init) {
ret = pci->pp.ops->init(&pci->pp);
if (ret) {
Expand All @@ -1241,8 +1247,21 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
return ret;

ret = dw_pcie_wait_for_link(pci);
if (ret)
return ret;
if (ret == -ETIMEDOUT)
goto err_stop_link;

if (pci->pp.ops->post_init)
pci->pp.ops->post_init(&pci->pp);

pci->suspended = false;

return 0;

err_stop_link:
dw_pcie_stop_link(pci);

if (pci->pp.ops->deinit)
pci->pp.ops->deinit(&pci->pp);

return ret;
}
Expand Down
86 changes: 84 additions & 2 deletions drivers/pci/controller/dwc/pcie-designware.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,9 +692,69 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
}

const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm)
{
const char *str;

switch (ltssm) {
#define DW_PCIE_LTSSM_NAME(n) case n: str = #n; break
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_QUIET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_ACT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_ACTIVE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_COMPLIANCE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_CONFIG);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_PRE_DETECT_QUIET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_WAIT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_START);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_ACEPT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_WAI);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_ACEPT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_COMPLETE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_LOCK);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_SPEED);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_RCVRCFG);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0S);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L123_SEND_EIDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_WAKE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_IDLE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ACTIVE);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT_TIMEOUT);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET_ENTRY);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ0);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ1);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ2);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ3);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_1);
DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_2);
default:
str = "DW_PCIE_LTSSM_UNKNOWN";
break;
}

return str + strlen("DW_PCIE_LTSSM_");
}

/**
* dw_pcie_wait_for_link - Wait for the PCIe link to be up
* @pci: DWC instance
*
* Returns: 0 if link is up, -ENODEV if device is not found, -EIO if the device
* is found but not active and -ETIMEDOUT if the link fails to come up for other
* reasons.
*/
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
u32 offset, val;
u32 offset, val, ltssm;
int retries;

/* Check if the link is up or not */
Expand All @@ -706,7 +766,29 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
}

if (retries >= PCIE_LINK_WAIT_MAX_RETRIES) {
dev_info(pci->dev, "Phy link never came up\n");
/*
* If the link is in Detect.Quiet or Detect.Active state, it
* indicates that no device is detected.
*/
ltssm = dw_pcie_get_ltssm(pci);
if (ltssm == DW_PCIE_LTSSM_DETECT_QUIET ||
ltssm == DW_PCIE_LTSSM_DETECT_ACT) {
dev_info(pci->dev, "Device not found\n");
return -ENODEV;

/*
* If the link is in POLL.{Active/Compliance} state, then the
* device is found to be connected to the bus, but it is not
* active i.e., the device firmware might not yet initialized.
*/
} else if (ltssm == DW_PCIE_LTSSM_POLL_ACTIVE ||
ltssm == DW_PCIE_LTSSM_POLL_COMPLIANCE) {
dev_info(pci->dev, "Device found, but not active\n");
return -EIO;
}

dev_err(pci->dev, "Link failed to come up. LTSSM: %s\n",
dw_pcie_ltssm_status_string(ltssm));
return -ETIMEDOUT;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-designware.h
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,8 @@ static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci)
return (enum dw_pcie_ltssm)FIELD_GET(PORT_LOGIC_LTSSM_STATE_MASK, val);
}

const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm);

#ifdef CONFIG_PCIE_DW_HOST
int dw_pcie_suspend_noirq(struct dw_pcie *pci);
int dw_pcie_resume_noirq(struct dw_pcie *pci);
Expand Down
Loading