Skip to content

Commit cedf8d8

Browse files
l1kdjbw
authored andcommitted
PCI/DOE: Relax restrictions on request and response size
An upcoming user of DOE is CMA (Component Measurement and Authentication, PCIe r6.0 sec 6.31). It builds on SPDM (Security Protocol and Data Model): https://www.dmtf.org/dsp/DSP0274 SPDM message sizes are not always a multiple of dwords. To transport them over DOE without using bounce buffers, allow sending requests and receiving responses whose final dword is only partially populated. To be clear, PCIe r6.0 sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords and pci_doe_send_req() and pci_doe_recv_resp() read/write dwords. So from a spec point of view, DOE is still specified in dwords and allowing non-dword request/response buffers is merely for the convenience of callers. Tested-by: Ira Weiny <ira.weiny@intel.com> Signed-off-by: Lukas Wunner <lukas@wunner.de> Reviewed-by: Ming Li <ming4.li@intel.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://lore.kernel.org/r/151b1a6a1794afb65d941287ecbc032c5b8004b9.1678543498.git.lukas@wunner.de Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 74e491e commit cedf8d8

1 file changed

Lines changed: 49 additions & 25 deletions

File tree

drivers/pci/doe.c

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ struct pci_doe_protocol {
7676
* @private: Private data for the consumer
7777
* @work: Used internally by the mailbox
7878
* @doe_mb: Used internally by the mailbox
79-
*
80-
* The payload sizes and rv are specified in bytes with the following
81-
* restrictions concerning the protocol.
82-
*
83-
* 1) The request_pl_sz must be a multiple of double words (4 bytes)
84-
* 2) The response_pl_sz must be >= a single double word (4 bytes)
85-
* 3) rv is returned as bytes but it will be a multiple of double words
8679
*/
8780
struct pci_doe_task {
8881
struct pci_doe_protocol prot;
@@ -153,7 +146,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
153146
{
154147
struct pci_dev *pdev = doe_mb->pdev;
155148
int offset = doe_mb->cap_offset;
156-
size_t length;
149+
size_t length, remainder;
157150
u32 val;
158151
int i;
159152

@@ -171,7 +164,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
171164
return -EIO;
172165

173166
/* Length is 2 DW of header + length of payload in DW */
174-
length = 2 + task->request_pl_sz / sizeof(__le32);
167+
length = 2 + DIV_ROUND_UP(task->request_pl_sz, sizeof(__le32));
175168
if (length > PCI_DOE_MAX_LENGTH)
176169
return -EIO;
177170
if (length == PCI_DOE_MAX_LENGTH)
@@ -184,10 +177,21 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
184177
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
185178
FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
186179
length));
180+
181+
/* Write payload */
187182
for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++)
188183
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
189184
le32_to_cpu(task->request_pl[i]));
190185

186+
/* Write last payload dword */
187+
remainder = task->request_pl_sz % sizeof(__le32);
188+
if (remainder) {
189+
val = 0;
190+
memcpy(&val, &task->request_pl[i], remainder);
191+
le32_to_cpus(&val);
192+
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
193+
}
194+
191195
pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
192196

193197
return 0;
@@ -207,11 +211,11 @@ static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb)
207211

208212
static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
209213
{
214+
size_t length, payload_length, remainder, received;
210215
struct pci_dev *pdev = doe_mb->pdev;
211216
int offset = doe_mb->cap_offset;
212-
size_t length, payload_length;
217+
int i = 0;
213218
u32 val;
214-
int i;
215219

216220
/* Read the first dword to get the protocol */
217221
pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
@@ -238,15 +242,38 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas
238242

239243
/* First 2 dwords have already been read */
240244
length -= 2;
241-
payload_length = min(length, task->response_pl_sz / sizeof(__le32));
242-
/* Read the rest of the response payload */
243-
for (i = 0; i < payload_length; i++) {
245+
received = task->response_pl_sz;
246+
payload_length = DIV_ROUND_UP(task->response_pl_sz, sizeof(__le32));
247+
remainder = task->response_pl_sz % sizeof(__le32);
248+
249+
/* remainder signifies number of data bytes in last payload dword */
250+
if (!remainder)
251+
remainder = sizeof(__le32);
252+
253+
if (length < payload_length) {
254+
received = length * sizeof(__le32);
255+
payload_length = length;
256+
remainder = sizeof(__le32);
257+
}
258+
259+
if (payload_length) {
260+
/* Read all payload dwords except the last */
261+
for (; i < payload_length - 1; i++) {
262+
pci_read_config_dword(pdev, offset + PCI_DOE_READ,
263+
&val);
264+
task->response_pl[i] = cpu_to_le32(val);
265+
pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
266+
}
267+
268+
/* Read last payload dword */
244269
pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
245-
task->response_pl[i] = cpu_to_le32(val);
270+
cpu_to_le32s(&val);
271+
memcpy(&task->response_pl[i], &val, remainder);
246272
/* Prior to the last ack, ensure Data Object Ready */
247-
if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb))
273+
if (!pci_doe_data_obj_ready(doe_mb))
248274
return -EIO;
249275
pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
276+
i++;
250277
}
251278

252279
/* Flush excess length */
@@ -260,7 +287,7 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas
260287
if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
261288
return -EIO;
262289

263-
return min(length, task->response_pl_sz / sizeof(__le32)) * sizeof(__le32);
290+
return received;
264291
}
265292

266293
static void signal_task_complete(struct pci_doe_task *task, int rv)
@@ -561,14 +588,6 @@ static int pci_doe_submit_task(struct pci_doe_mb *doe_mb,
561588
if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type))
562589
return -EINVAL;
563590

564-
/*
565-
* DOE requests must be a whole number of DW and the response needs to
566-
* be big enough for at least 1 DW
567-
*/
568-
if (task->request_pl_sz % sizeof(__le32) ||
569-
task->response_pl_sz < sizeof(__le32))
570-
return -EINVAL;
571-
572591
if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
573592
return -EIO;
574593

@@ -596,6 +615,11 @@ static int pci_doe_submit_task(struct pci_doe_mb *doe_mb,
596615
* without byte-swapping. If payloads contain little-endian register values,
597616
* the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu().
598617
*
618+
* For convenience, arbitrary payload sizes are allowed even though PCIe r6.0
619+
* sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords. The last
620+
* (partial) dword is copied with byte granularity and padded with zeroes if
621+
* necessary. Callers are thus relieved of using dword-sized bounce buffers.
622+
*
599623
* RETURNS: Length of received response or negative errno.
600624
* Received data in excess of @response_sz is discarded.
601625
* The length may be smaller than @response_sz and the caller

0 commit comments

Comments
 (0)