Skip to content

Commit ce17ad0

Browse files
davejiangdjbw
authored andcommitted
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: 523e594 ("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>
1 parent eb0764b commit ce17ad0

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

drivers/cxl/core/pci.c

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,57 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port)
101101
}
102102
EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);
103103

104-
/*
105-
* Wait up to @media_ready_timeout for the device to report memory
106-
* active.
107-
*/
108-
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
104+
static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
105+
{
106+
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
107+
int d = cxlds->cxl_dvsec;
108+
bool valid = false;
109+
int rc, i;
110+
u32 temp;
111+
112+
if (id > CXL_DVSEC_RANGE_MAX)
113+
return -EINVAL;
114+
115+
/* Check MEM INFO VALID bit first, give up after 1s */
116+
i = 1;
117+
do {
118+
rc = pci_read_config_dword(pdev,
119+
d + CXL_DVSEC_RANGE_SIZE_LOW(id),
120+
&temp);
121+
if (rc)
122+
return rc;
123+
124+
valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
125+
if (valid)
126+
break;
127+
msleep(1000);
128+
} while (i--);
129+
130+
if (!valid) {
131+
dev_err(&pdev->dev,
132+
"Timeout awaiting memory range %d valid after 1s.\n",
133+
id);
134+
return -ETIMEDOUT;
135+
}
136+
137+
return 0;
138+
}
139+
140+
static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
109141
{
110142
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
111143
int d = cxlds->cxl_dvsec;
112144
bool active = false;
113-
u64 md_status;
114145
int rc, i;
146+
u32 temp;
115147

116-
for (i = media_ready_timeout; i; i--) {
117-
u32 temp;
148+
if (id > CXL_DVSEC_RANGE_MAX)
149+
return -EINVAL;
118150

151+
/* Check MEM ACTIVE bit, up to 60s timeout by default */
152+
for (i = media_ready_timeout; i; i--) {
119153
rc = pci_read_config_dword(
120-
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
154+
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp);
121155
if (rc)
122156
return rc;
123157

@@ -134,6 +168,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
134168
return -ETIMEDOUT;
135169
}
136170

171+
return 0;
172+
}
173+
174+
/*
175+
* Wait up to @media_ready_timeout for the device to report memory
176+
* active.
177+
*/
178+
int cxl_await_media_ready(struct cxl_dev_state *cxlds)
179+
{
180+
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
181+
int d = cxlds->cxl_dvsec;
182+
int rc, i, hdm_count;
183+
u64 md_status;
184+
u16 cap;
185+
186+
rc = pci_read_config_word(pdev,
187+
d + CXL_DVSEC_CAP_OFFSET, &cap);
188+
if (rc)
189+
return rc;
190+
191+
hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
192+
for (i = 0; i < hdm_count; i++) {
193+
rc = cxl_dvsec_mem_range_valid(cxlds, i);
194+
if (rc)
195+
return rc;
196+
}
197+
198+
for (i = 0; i < hdm_count; i++) {
199+
rc = cxl_dvsec_mem_range_active(cxlds, i);
200+
if (rc)
201+
return rc;
202+
}
203+
137204
md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
138205
if (!CXLMDEV_READY(md_status))
139206
return -EIO;

drivers/cxl/cxlpci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
3232
#define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28)
3333

34+
#define CXL_DVSEC_RANGE_MAX 2
35+
3436
/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
3537
#define CXL_DVSEC_FUNCTION_MAP 2
3638

0 commit comments

Comments
 (0)