Skip to content

Commit d0abf57

Browse files
AlisonSchofielddjbw
authored andcommitted
cxl/mbox: Initialize the poison state
Driver reads of the poison list are synchronized to ensure that a reader does not get an incomplete list because their request overlapped (was interrupted or preceded by) another read request of the same DPA range. (CXL Spec 3.0 Section 8.2.9.8.4.1). The driver maintains state information to achieve this goal. To initialize the state, first recognize the poison commands in the CEL (Command Effects Log). If the device supports Get Poison List, allocate a single buffer for the poison list and protect it with a lock. Signed-off-by: Alison Schofield <alison.schofield@intel.com> Link: https://lore.kernel.org/r/9078d180769be28a5087288b38cdfc827cae58bf.1681838291.git.alison.schofield@intel.com Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Tested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent dec441d commit d0abf57

3 files changed

Lines changed: 117 additions & 2 deletions

File tree

drivers/cxl/core/mbox.c

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/debugfs.h>
66
#include <linux/ktime.h>
77
#include <linux/mutex.h>
8+
#include <cxlpci.h>
89
#include <cxlmem.h>
910
#include <cxl.h>
1011

@@ -120,6 +121,43 @@ static bool cxl_is_security_command(u16 opcode)
120121
return false;
121122
}
122123

124+
static bool cxl_is_poison_command(u16 opcode)
125+
{
126+
#define CXL_MBOX_OP_POISON_CMDS 0x43
127+
128+
if ((opcode >> 8) == CXL_MBOX_OP_POISON_CMDS)
129+
return true;
130+
131+
return false;
132+
}
133+
134+
static void cxl_set_poison_cmd_enabled(struct cxl_poison_state *poison,
135+
u16 opcode)
136+
{
137+
switch (opcode) {
138+
case CXL_MBOX_OP_GET_POISON:
139+
set_bit(CXL_POISON_ENABLED_LIST, poison->enabled_cmds);
140+
break;
141+
case CXL_MBOX_OP_INJECT_POISON:
142+
set_bit(CXL_POISON_ENABLED_INJECT, poison->enabled_cmds);
143+
break;
144+
case CXL_MBOX_OP_CLEAR_POISON:
145+
set_bit(CXL_POISON_ENABLED_CLEAR, poison->enabled_cmds);
146+
break;
147+
case CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS:
148+
set_bit(CXL_POISON_ENABLED_SCAN_CAPS, poison->enabled_cmds);
149+
break;
150+
case CXL_MBOX_OP_SCAN_MEDIA:
151+
set_bit(CXL_POISON_ENABLED_SCAN_MEDIA, poison->enabled_cmds);
152+
break;
153+
case CXL_MBOX_OP_GET_SCAN_MEDIA:
154+
set_bit(CXL_POISON_ENABLED_SCAN_RESULTS, poison->enabled_cmds);
155+
break;
156+
default:
157+
break;
158+
}
159+
}
160+
123161
static struct cxl_mem_command *cxl_mem_find_command(u16 opcode)
124162
{
125163
struct cxl_mem_command *c;
@@ -635,13 +673,18 @@ static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel)
635673
u16 opcode = le16_to_cpu(cel_entry[i].opcode);
636674
struct cxl_mem_command *cmd = cxl_mem_find_command(opcode);
637675

638-
if (!cmd) {
676+
if (!cmd && !cxl_is_poison_command(opcode)) {
639677
dev_dbg(cxlds->dev,
640678
"Opcode 0x%04x unsupported by driver\n", opcode);
641679
continue;
642680
}
643681

644-
set_bit(cmd->info.id, cxlds->enabled_cmds);
682+
if (cmd)
683+
set_bit(cmd->info.id, cxlds->enabled_cmds);
684+
685+
if (cxl_is_poison_command(opcode))
686+
cxl_set_poison_cmd_enabled(&cxlds->poison, opcode);
687+
645688
dev_dbg(cxlds->dev, "Opcode 0x%04x enabled\n", opcode);
646689
}
647690
}
@@ -1108,6 +1151,40 @@ int cxl_set_timestamp(struct cxl_dev_state *cxlds)
11081151
}
11091152
EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL);
11101153

1154+
static void free_poison_buf(void *buf)
1155+
{
1156+
kvfree(buf);
1157+
}
1158+
1159+
/* Get Poison List output buffer is protected by cxlds->poison.lock */
1160+
static int cxl_poison_alloc_buf(struct cxl_dev_state *cxlds)
1161+
{
1162+
cxlds->poison.list_out = kvmalloc(cxlds->payload_size, GFP_KERNEL);
1163+
if (!cxlds->poison.list_out)
1164+
return -ENOMEM;
1165+
1166+
return devm_add_action_or_reset(cxlds->dev, free_poison_buf,
1167+
cxlds->poison.list_out);
1168+
}
1169+
1170+
int cxl_poison_state_init(struct cxl_dev_state *cxlds)
1171+
{
1172+
int rc;
1173+
1174+
if (!test_bit(CXL_POISON_ENABLED_LIST, cxlds->poison.enabled_cmds))
1175+
return 0;
1176+
1177+
rc = cxl_poison_alloc_buf(cxlds);
1178+
if (rc) {
1179+
clear_bit(CXL_POISON_ENABLED_LIST, cxlds->poison.enabled_cmds);
1180+
return rc;
1181+
}
1182+
1183+
mutex_init(&cxlds->poison.lock);
1184+
return 0;
1185+
}
1186+
EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, CXL);
1187+
11111188
struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
11121189
{
11131190
struct cxl_dev_state *cxlds;

drivers/cxl/cxlmem.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,37 @@ struct cxl_event_state {
215215
struct mutex log_lock;
216216
};
217217

218+
/* Device enabled poison commands */
219+
enum poison_cmd_enabled_bits {
220+
CXL_POISON_ENABLED_LIST,
221+
CXL_POISON_ENABLED_INJECT,
222+
CXL_POISON_ENABLED_CLEAR,
223+
CXL_POISON_ENABLED_SCAN_CAPS,
224+
CXL_POISON_ENABLED_SCAN_MEDIA,
225+
CXL_POISON_ENABLED_SCAN_RESULTS,
226+
CXL_POISON_ENABLED_MAX
227+
};
228+
229+
/**
230+
* struct cxl_poison_state - Driver poison state info
231+
*
232+
* @max_errors: Maximum media error records held in device cache
233+
* @enabled_cmds: All poison commands enabled in the CEL
234+
* @list_out: The poison list payload returned by device
235+
* @lock: Protect reads of the poison list
236+
*
237+
* Reads of the poison list are synchronized to ensure that a reader
238+
* does not get an incomplete list because their request overlapped
239+
* (was interrupted or preceded by) another read request of the same
240+
* DPA range. CXL Spec 3.0 Section 8.2.9.8.4.1
241+
*/
242+
struct cxl_poison_state {
243+
u32 max_errors;
244+
DECLARE_BITMAP(enabled_cmds, CXL_POISON_ENABLED_MAX);
245+
struct cxl_mbox_poison_out *list_out;
246+
struct mutex lock; /* Protect reads of poison list */
247+
};
248+
218249
/**
219250
* struct cxl_dev_state - The driver device state
220251
*
@@ -251,6 +282,7 @@ struct cxl_event_state {
251282
* @serial: PCIe Device Serial Number
252283
* @doe_mbs: PCI DOE mailbox array
253284
* @event: event log driver state
285+
* @poison: poison driver state info
254286
* @mbox_send: @dev specific transport for transmitting mailbox commands
255287
*
256288
* See section 8.2.9.5.2 Capacity Configuration and Label Storage for
@@ -290,6 +322,7 @@ struct cxl_dev_state {
290322
struct xarray doe_mbs;
291323

292324
struct cxl_event_state event;
325+
struct cxl_poison_state poison;
293326

294327
int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
295328
};
@@ -608,6 +641,7 @@ void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds
608641
void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds);
609642
void cxl_mem_get_event_records(struct cxl_dev_state *cxlds, u32 status);
610643
int cxl_set_timestamp(struct cxl_dev_state *cxlds);
644+
int cxl_poison_state_init(struct cxl_dev_state *cxlds);
611645

612646
#ifdef CONFIG_CXL_SUSPEND
613647
void cxl_mem_active_inc(void);

drivers/cxl/pci.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
769769
if (rc)
770770
return rc;
771771

772+
rc = cxl_poison_state_init(cxlds);
773+
if (rc)
774+
return rc;
775+
772776
rc = cxl_dev_state_identify(cxlds);
773777
if (rc)
774778
return rc;

0 commit comments

Comments
 (0)