mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 23:23:03 +00:00
cxl: Wait Memory_Info_Valid before access memory related info
The Memory_Info_Valid bit (CXL 3.0 8.1.3.8.2) indicates that the CXL
Range Size High and Size Low registers are valid. The bit must be set
within 1 second of reset deassertion to the device. Check valid bit
before we check the Memory_Active bit when waiting for
cxl_await_media_ready() to ensure that the memory info is valid for
consumption. Also ensures both DVSEC ranges 1 and 2 are ready if DVSEC
Capability indicates they are both supported.
Fixes: 523e594d9c
("cxl/pci: Implement wait for media active")
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/168444687469.3134781.11033518965387297327.stgit@djiang5-mobl3
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
eb0764b822
commit
ce17ad0d54
@ -101,23 +101,57 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);
|
||||
|
||||
/*
|
||||
* Wait up to @media_ready_timeout for the device to report memory
|
||||
* active.
|
||||
*/
|
||||
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
|
||||
static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
int d = cxlds->cxl_dvsec;
|
||||
bool valid = false;
|
||||
int rc, i;
|
||||
u32 temp;
|
||||
|
||||
if (id > CXL_DVSEC_RANGE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check MEM INFO VALID bit first, give up after 1s */
|
||||
i = 1;
|
||||
do {
|
||||
rc = pci_read_config_dword(pdev,
|
||||
d + CXL_DVSEC_RANGE_SIZE_LOW(id),
|
||||
&temp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
|
||||
if (valid)
|
||||
break;
|
||||
msleep(1000);
|
||||
} while (i--);
|
||||
|
||||
if (!valid) {
|
||||
dev_err(&pdev->dev,
|
||||
"Timeout awaiting memory range %d valid after 1s.\n",
|
||||
id);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
int d = cxlds->cxl_dvsec;
|
||||
bool active = false;
|
||||
u64 md_status;
|
||||
int rc, i;
|
||||
u32 temp;
|
||||
|
||||
if (id > CXL_DVSEC_RANGE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check MEM ACTIVE bit, up to 60s timeout by default */
|
||||
for (i = media_ready_timeout; i; i--) {
|
||||
u32 temp;
|
||||
|
||||
rc = pci_read_config_dword(
|
||||
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
|
||||
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -134,6 +168,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait up to @media_ready_timeout for the device to report memory
|
||||
* active.
|
||||
*/
|
||||
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
int d = cxlds->cxl_dvsec;
|
||||
int rc, i, hdm_count;
|
||||
u64 md_status;
|
||||
u16 cap;
|
||||
|
||||
rc = pci_read_config_word(pdev,
|
||||
d + CXL_DVSEC_CAP_OFFSET, &cap);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
|
||||
for (i = 0; i < hdm_count; i++) {
|
||||
rc = cxl_dvsec_mem_range_valid(cxlds, i);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdm_count; i++) {
|
||||
rc = cxl_dvsec_mem_range_active(cxlds, i);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
|
||||
if (!CXLMDEV_READY(md_status))
|
||||
return -EIO;
|
||||
|
@ -31,6 +31,8 @@
|
||||
#define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
|
||||
#define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28)
|
||||
|
||||
#define CXL_DVSEC_RANGE_MAX 2
|
||||
|
||||
/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
|
||||
#define CXL_DVSEC_FUNCTION_MAP 2
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user