Commit | Line | Data |
---|---|---|
9d24322e JC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Data Object Exchange | |
4 | * PCIe r6.0, sec 6.30 DOE | |
5 | * | |
6 | * Copyright (C) 2021 Huawei | |
7 | * Jonathan Cameron <Jonathan.Cameron@huawei.com> | |
8 | * | |
9 | * Copyright (C) 2022 Intel Corporation | |
10 | * Ira Weiny <ira.weiny@intel.com> | |
11 | */ | |
12 | ||
13 | #define dev_fmt(fmt) "DOE: " fmt | |
14 | ||
15 | #include <linux/bitfield.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/jiffies.h> | |
18 | #include <linux/mutex.h> | |
19 | #include <linux/pci.h> | |
20 | #include <linux/pci-doe.h> | |
21 | #include <linux/workqueue.h> | |
22 | ||
ac048403 LW |
23 | #include "pci.h" |
24 | ||
9d24322e JC |
25 | #define PCI_DOE_PROTOCOL_DISCOVERY 0 |
26 | ||
27 | /* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */ | |
28 | #define PCI_DOE_TIMEOUT HZ | |
29 | #define PCI_DOE_POLL_INTERVAL (PCI_DOE_TIMEOUT / 128) | |
30 | ||
31 | #define PCI_DOE_FLAG_CANCEL 0 | |
32 | #define PCI_DOE_FLAG_DEAD 1 | |
33 | ||
a4ff8e7a LM |
34 | /* Max data object length is 2^18 dwords */ |
35 | #define PCI_DOE_MAX_LENGTH (1 << 18) | |
36 | ||
9d24322e JC |
37 | /** |
38 | * struct pci_doe_mb - State for a single DOE mailbox | |
39 | * | |
40 | * This state is used to manage a single DOE mailbox capability. All fields | |
41 | * should be considered opaque to the consumers and the structure passed into | |
022b66f3 | 42 | * the helpers below after being created by pci_doe_create_mb(). |
9d24322e JC |
43 | * |
44 | * @pdev: PCI device this mailbox belongs to | |
45 | * @cap_offset: Capability offset | |
46 | * @prots: Array of protocols supported (encoded as long values) | |
47 | * @wq: Wait queue for work item | |
48 | * @work_queue: Queue of pci_doe_work items | |
49 | * @flags: Bit array of PCI_DOE_FLAG_* flags | |
50 | */ | |
51 | struct pci_doe_mb { | |
52 | struct pci_dev *pdev; | |
53 | u16 cap_offset; | |
54 | struct xarray prots; | |
55 | ||
56 | wait_queue_head_t wq; | |
57 | struct workqueue_struct *work_queue; | |
58 | unsigned long flags; | |
59 | }; | |
60 | ||
0821ff8e LW |
61 | struct pci_doe_protocol { |
62 | u16 vid; | |
63 | u8 type; | |
64 | }; | |
65 | ||
66 | /** | |
67 | * struct pci_doe_task - represents a single query/response | |
68 | * | |
69 | * @prot: DOE Protocol | |
70 | * @request_pl: The request payload | |
71 | * @request_pl_sz: Size of the request payload (bytes) | |
72 | * @response_pl: The response payload | |
73 | * @response_pl_sz: Size of the response payload (bytes) | |
74 | * @rv: Return value. Length of received response or error (bytes) | |
75 | * @complete: Called when task is complete | |
76 | * @private: Private data for the consumer | |
77 | * @work: Used internally by the mailbox | |
78 | * @doe_mb: Used internally by the mailbox | |
0821ff8e LW |
79 | */ |
80 | struct pci_doe_task { | |
81 | struct pci_doe_protocol prot; | |
82 | const __le32 *request_pl; | |
83 | size_t request_pl_sz; | |
84 | __le32 *response_pl; | |
85 | size_t response_pl_sz; | |
86 | int rv; | |
87 | void (*complete)(struct pci_doe_task *task); | |
88 | void *private; | |
89 | ||
90 | /* initialized by pci_doe_submit_task() */ | |
91 | struct work_struct work; | |
92 | struct pci_doe_mb *doe_mb; | |
93 | }; | |
94 | ||
9d24322e JC |
95 | static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout) |
96 | { | |
97 | if (wait_event_timeout(doe_mb->wq, | |
98 | test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags), | |
99 | timeout)) | |
100 | return -EIO; | |
101 | return 0; | |
102 | } | |
103 | ||
104 | static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val) | |
105 | { | |
106 | struct pci_dev *pdev = doe_mb->pdev; | |
107 | int offset = doe_mb->cap_offset; | |
108 | ||
109 | pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val); | |
110 | } | |
111 | ||
112 | static int pci_doe_abort(struct pci_doe_mb *doe_mb) | |
113 | { | |
114 | struct pci_dev *pdev = doe_mb->pdev; | |
115 | int offset = doe_mb->cap_offset; | |
116 | unsigned long timeout_jiffies; | |
117 | ||
118 | pci_dbg(pdev, "[%x] Issuing Abort\n", offset); | |
119 | ||
120 | timeout_jiffies = jiffies + PCI_DOE_TIMEOUT; | |
121 | pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT); | |
122 | ||
123 | do { | |
124 | int rc; | |
125 | u32 val; | |
126 | ||
127 | rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL); | |
128 | if (rc) | |
129 | return rc; | |
130 | pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); | |
131 | ||
132 | /* Abort success! */ | |
133 | if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) && | |
134 | !FIELD_GET(PCI_DOE_STATUS_BUSY, val)) | |
135 | return 0; | |
136 | ||
137 | } while (!time_after(jiffies, timeout_jiffies)); | |
138 | ||
139 | /* Abort has timed out and the MB is dead */ | |
140 | pci_err(pdev, "[%x] ABORT timed out\n", offset); | |
141 | return -EIO; | |
142 | } | |
143 | ||
144 | static int pci_doe_send_req(struct pci_doe_mb *doe_mb, | |
145 | struct pci_doe_task *task) | |
146 | { | |
147 | struct pci_dev *pdev = doe_mb->pdev; | |
148 | int offset = doe_mb->cap_offset; | |
cedf8d8a | 149 | size_t length, remainder; |
9d24322e JC |
150 | u32 val; |
151 | int i; | |
152 | ||
153 | /* | |
154 | * Check the DOE busy bit is not set. If it is set, this could indicate | |
155 | * someone other than Linux (e.g. firmware) is using the mailbox. Note | |
156 | * it is expected that firmware and OS will negotiate access rights via | |
157 | * an, as yet to be defined, method. | |
158 | */ | |
159 | pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); | |
160 | if (FIELD_GET(PCI_DOE_STATUS_BUSY, val)) | |
161 | return -EBUSY; | |
162 | ||
163 | if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) | |
164 | return -EIO; | |
165 | ||
a4ff8e7a | 166 | /* Length is 2 DW of header + length of payload in DW */ |
cedf8d8a | 167 | length = 2 + DIV_ROUND_UP(task->request_pl_sz, sizeof(__le32)); |
a4ff8e7a LM |
168 | if (length > PCI_DOE_MAX_LENGTH) |
169 | return -EIO; | |
170 | if (length == PCI_DOE_MAX_LENGTH) | |
171 | length = 0; | |
172 | ||
9d24322e JC |
173 | /* Write DOE Header */ |
174 | val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) | | |
175 | FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type); | |
176 | pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val); | |
9d24322e JC |
177 | pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, |
178 | FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, | |
a4ff8e7a | 179 | length)); |
cedf8d8a LW |
180 | |
181 | /* Write payload */ | |
fbaa3821 | 182 | for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++) |
9d24322e | 183 | pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, |
fbaa3821 | 184 | le32_to_cpu(task->request_pl[i])); |
9d24322e | 185 | |
cedf8d8a LW |
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 | ||
9d24322e JC |
195 | pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO); |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb) | |
201 | { | |
202 | struct pci_dev *pdev = doe_mb->pdev; | |
203 | int offset = doe_mb->cap_offset; | |
204 | u32 val; | |
205 | ||
206 | pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); | |
207 | if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) | |
208 | return true; | |
209 | return false; | |
210 | } | |
211 | ||
212 | static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) | |
213 | { | |
cedf8d8a | 214 | size_t length, payload_length, remainder, received; |
9d24322e JC |
215 | struct pci_dev *pdev = doe_mb->pdev; |
216 | int offset = doe_mb->cap_offset; | |
cedf8d8a | 217 | int i = 0; |
9d24322e | 218 | u32 val; |
9d24322e JC |
219 | |
220 | /* Read the first dword to get the protocol */ | |
221 | pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); | |
222 | if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) || | |
223 | (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) { | |
224 | dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n", | |
225 | doe_mb->cap_offset, task->prot.vid, task->prot.type, | |
226 | FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val), | |
227 | FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val)); | |
228 | return -EIO; | |
229 | } | |
230 | ||
231 | pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); | |
232 | /* Read the second dword to get the length */ | |
233 | pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); | |
234 | pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); | |
235 | ||
236 | length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val); | |
a4ff8e7a LM |
237 | /* A value of 0x0 indicates max data object length */ |
238 | if (!length) | |
239 | length = PCI_DOE_MAX_LENGTH; | |
240 | if (length < 2) | |
9d24322e JC |
241 | return -EIO; |
242 | ||
243 | /* First 2 dwords have already been read */ | |
244 | length -= 2; | |
cedf8d8a LW |
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 */ | |
fbaa3821 | 269 | pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); |
cedf8d8a LW |
270 | cpu_to_le32s(&val); |
271 | memcpy(&task->response_pl[i], &val, remainder); | |
9d24322e | 272 | /* Prior to the last ack, ensure Data Object Ready */ |
cedf8d8a | 273 | if (!pci_doe_data_obj_ready(doe_mb)) |
9d24322e JC |
274 | return -EIO; |
275 | pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); | |
cedf8d8a | 276 | i++; |
9d24322e JC |
277 | } |
278 | ||
279 | /* Flush excess length */ | |
280 | for (; i < length; i++) { | |
281 | pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); | |
282 | pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); | |
283 | } | |
284 | ||
285 | /* Final error check to pick up on any since Data Object Ready */ | |
286 | pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); | |
287 | if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) | |
288 | return -EIO; | |
289 | ||
cedf8d8a | 290 | return received; |
9d24322e JC |
291 | } |
292 | ||
293 | static void signal_task_complete(struct pci_doe_task *task, int rv) | |
294 | { | |
295 | task->rv = rv; | |
abf04be0 | 296 | destroy_work_on_stack(&task->work); |
e3a3a097 | 297 | task->complete(task); |
9d24322e JC |
298 | } |
299 | ||
300 | static void signal_task_abort(struct pci_doe_task *task, int rv) | |
301 | { | |
302 | struct pci_doe_mb *doe_mb = task->doe_mb; | |
303 | struct pci_dev *pdev = doe_mb->pdev; | |
304 | ||
305 | if (pci_doe_abort(doe_mb)) { | |
306 | /* | |
307 | * If the device can't process an abort; set the mailbox dead | |
308 | * - no more submissions | |
309 | */ | |
310 | pci_err(pdev, "[%x] Abort failed marking mailbox dead\n", | |
311 | doe_mb->cap_offset); | |
312 | set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags); | |
313 | } | |
314 | signal_task_complete(task, rv); | |
315 | } | |
316 | ||
317 | static void doe_statemachine_work(struct work_struct *work) | |
318 | { | |
319 | struct pci_doe_task *task = container_of(work, struct pci_doe_task, | |
320 | work); | |
321 | struct pci_doe_mb *doe_mb = task->doe_mb; | |
322 | struct pci_dev *pdev = doe_mb->pdev; | |
323 | int offset = doe_mb->cap_offset; | |
324 | unsigned long timeout_jiffies; | |
325 | u32 val; | |
326 | int rc; | |
327 | ||
328 | if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) { | |
329 | signal_task_complete(task, -EIO); | |
330 | return; | |
331 | } | |
332 | ||
333 | /* Send request */ | |
334 | rc = pci_doe_send_req(doe_mb, task); | |
335 | if (rc) { | |
336 | /* | |
337 | * The specification does not provide any guidance on how to | |
338 | * resolve conflicting requests from other entities. | |
339 | * Furthermore, it is likely that busy will not be detected | |
340 | * most of the time. Flag any detection of status busy with an | |
341 | * error. | |
342 | */ | |
343 | if (rc == -EBUSY) | |
344 | dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n", | |
345 | offset); | |
346 | signal_task_abort(task, rc); | |
347 | return; | |
348 | } | |
349 | ||
350 | timeout_jiffies = jiffies + PCI_DOE_TIMEOUT; | |
351 | /* Poll for response */ | |
352 | retry_resp: | |
353 | pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); | |
354 | if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) { | |
355 | signal_task_abort(task, -EIO); | |
356 | return; | |
357 | } | |
358 | ||
359 | if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) { | |
360 | if (time_after(jiffies, timeout_jiffies)) { | |
361 | signal_task_abort(task, -EIO); | |
362 | return; | |
363 | } | |
364 | rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL); | |
365 | if (rc) { | |
366 | signal_task_abort(task, rc); | |
367 | return; | |
368 | } | |
369 | goto retry_resp; | |
370 | } | |
371 | ||
372 | rc = pci_doe_recv_resp(doe_mb, task); | |
373 | if (rc < 0) { | |
374 | signal_task_abort(task, rc); | |
375 | return; | |
376 | } | |
377 | ||
378 | signal_task_complete(task, rc); | |
379 | } | |
380 | ||
381 | static void pci_doe_task_complete(struct pci_doe_task *task) | |
382 | { | |
383 | complete(task->private); | |
384 | } | |
385 | ||
eebab7e3 | 386 | static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 capver, u8 *index, u16 *vid, |
9d24322e JC |
387 | u8 *protocol) |
388 | { | |
389 | u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX, | |
eebab7e3 AK |
390 | *index) | |
391 | FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_VER, | |
392 | (capver >= 2) ? 2 : 0); | |
fbaa3821 LW |
393 | __le32 request_pl_le = cpu_to_le32(request_pl); |
394 | __le32 response_pl_le; | |
9d24322e | 395 | u32 response_pl; |
9d24322e JC |
396 | int rc; |
397 | ||
62e8b17f LW |
398 | rc = pci_doe(doe_mb, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_PROTOCOL_DISCOVERY, |
399 | &request_pl_le, sizeof(request_pl_le), | |
400 | &response_pl_le, sizeof(response_pl_le)); | |
9d24322e JC |
401 | if (rc < 0) |
402 | return rc; | |
403 | ||
62e8b17f | 404 | if (rc != sizeof(response_pl_le)) |
9d24322e JC |
405 | return -EIO; |
406 | ||
fbaa3821 | 407 | response_pl = le32_to_cpu(response_pl_le); |
9d24322e JC |
408 | *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl); |
409 | *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL, | |
410 | response_pl); | |
411 | *index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX, | |
412 | response_pl); | |
413 | ||
414 | return 0; | |
415 | } | |
416 | ||
417 | static void *pci_doe_xa_prot_entry(u16 vid, u8 prot) | |
418 | { | |
419 | return xa_mk_value((vid << 8) | prot); | |
420 | } | |
421 | ||
422 | static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb) | |
423 | { | |
424 | u8 index = 0; | |
425 | u8 xa_idx = 0; | |
eebab7e3 AK |
426 | u32 hdr = 0; |
427 | ||
428 | pci_read_config_dword(doe_mb->pdev, doe_mb->cap_offset, &hdr); | |
9d24322e JC |
429 | |
430 | do { | |
431 | int rc; | |
432 | u16 vid; | |
433 | u8 prot; | |
434 | ||
eebab7e3 AK |
435 | rc = pci_doe_discovery(doe_mb, PCI_EXT_CAP_VER(hdr), &index, |
436 | &vid, &prot); | |
9d24322e JC |
437 | if (rc) |
438 | return rc; | |
439 | ||
440 | pci_dbg(doe_mb->pdev, | |
441 | "[%x] Found protocol %d vid: %x prot: %x\n", | |
442 | doe_mb->cap_offset, xa_idx, vid, prot); | |
443 | ||
444 | rc = xa_insert(&doe_mb->prots, xa_idx++, | |
445 | pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL); | |
446 | if (rc) | |
447 | return rc; | |
448 | } while (index); | |
449 | ||
450 | return 0; | |
451 | } | |
452 | ||
022b66f3 | 453 | static void pci_doe_cancel_tasks(struct pci_doe_mb *doe_mb) |
9d24322e | 454 | { |
9d24322e JC |
455 | /* Stop all pending work items from starting */ |
456 | set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags); | |
457 | ||
458 | /* Cancel an in progress work item, if necessary */ | |
459 | set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags); | |
460 | wake_up(&doe_mb->wq); | |
9d24322e JC |
461 | } |
462 | ||
463 | /** | |
022b66f3 | 464 | * pci_doe_create_mb() - Create a DOE mailbox object |
9d24322e JC |
465 | * |
466 | * @pdev: PCI device to create the DOE mailbox for | |
467 | * @cap_offset: Offset of the DOE mailbox | |
468 | * | |
469 | * Create a single mailbox object to manage the mailbox protocol at the | |
470 | * cap_offset specified. | |
471 | * | |
472 | * RETURNS: created mailbox object on success | |
473 | * ERR_PTR(-errno) on failure | |
474 | */ | |
022b66f3 LW |
475 | static struct pci_doe_mb *pci_doe_create_mb(struct pci_dev *pdev, |
476 | u16 cap_offset) | |
9d24322e JC |
477 | { |
478 | struct pci_doe_mb *doe_mb; | |
9d24322e JC |
479 | int rc; |
480 | ||
022b66f3 | 481 | doe_mb = kzalloc(sizeof(*doe_mb), GFP_KERNEL); |
9d24322e JC |
482 | if (!doe_mb) |
483 | return ERR_PTR(-ENOMEM); | |
484 | ||
485 | doe_mb->pdev = pdev; | |
486 | doe_mb->cap_offset = cap_offset; | |
487 | init_waitqueue_head(&doe_mb->wq); | |
9d24322e | 488 | xa_init(&doe_mb->prots); |
9d24322e JC |
489 | |
490 | doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0, | |
74e491e5 | 491 | dev_bus_name(&pdev->dev), |
9d24322e JC |
492 | pci_name(pdev), |
493 | doe_mb->cap_offset); | |
494 | if (!doe_mb->work_queue) { | |
495 | pci_err(pdev, "[%x] failed to allocate work queue\n", | |
496 | doe_mb->cap_offset); | |
022b66f3 LW |
497 | rc = -ENOMEM; |
498 | goto err_free; | |
9d24322e | 499 | } |
9d24322e JC |
500 | |
501 | /* Reset the mailbox by issuing an abort */ | |
502 | rc = pci_doe_abort(doe_mb); | |
503 | if (rc) { | |
504 | pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n", | |
505 | doe_mb->cap_offset, rc); | |
022b66f3 | 506 | goto err_destroy_wq; |
9d24322e JC |
507 | } |
508 | ||
509 | /* | |
510 | * The state machine and the mailbox should be in sync now; | |
022b66f3 | 511 | * Use the mailbox to query protocols. |
9d24322e | 512 | */ |
9d24322e JC |
513 | rc = pci_doe_cache_protocols(doe_mb); |
514 | if (rc) { | |
515 | pci_err(pdev, "[%x] failed to cache protocols : %d\n", | |
516 | doe_mb->cap_offset, rc); | |
022b66f3 | 517 | goto err_cancel; |
9d24322e JC |
518 | } |
519 | ||
520 | return doe_mb; | |
022b66f3 LW |
521 | |
522 | err_cancel: | |
523 | pci_doe_cancel_tasks(doe_mb); | |
524 | xa_destroy(&doe_mb->prots); | |
525 | err_destroy_wq: | |
526 | destroy_workqueue(doe_mb->work_queue); | |
527 | err_free: | |
528 | kfree(doe_mb); | |
529 | return ERR_PTR(rc); | |
530 | } | |
531 | ||
532 | /** | |
533 | * pci_doe_destroy_mb() - Destroy a DOE mailbox object | |
534 | * | |
74e491e5 | 535 | * @doe_mb: DOE mailbox |
022b66f3 LW |
536 | * |
537 | * Destroy all internal data structures created for the DOE mailbox. | |
538 | */ | |
74e491e5 | 539 | static void pci_doe_destroy_mb(struct pci_doe_mb *doe_mb) |
022b66f3 | 540 | { |
022b66f3 LW |
541 | pci_doe_cancel_tasks(doe_mb); |
542 | xa_destroy(&doe_mb->prots); | |
543 | destroy_workqueue(doe_mb->work_queue); | |
544 | kfree(doe_mb); | |
545 | } | |
546 | ||
9d24322e JC |
547 | /** |
548 | * pci_doe_supports_prot() - Return if the DOE instance supports the given | |
549 | * protocol | |
550 | * @doe_mb: DOE mailbox capability to query | |
551 | * @vid: Protocol Vendor ID | |
552 | * @type: Protocol type | |
553 | * | |
554 | * RETURNS: True if the DOE mailbox supports the protocol specified | |
555 | */ | |
74e491e5 | 556 | static bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type) |
9d24322e JC |
557 | { |
558 | unsigned long index; | |
559 | void *entry; | |
560 | ||
561 | /* The discovery protocol must always be supported */ | |
562 | if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY) | |
563 | return true; | |
564 | ||
565 | xa_for_each(&doe_mb->prots, index, entry) | |
566 | if (entry == pci_doe_xa_prot_entry(vid, type)) | |
567 | return true; | |
568 | ||
569 | return false; | |
570 | } | |
9d24322e JC |
571 | |
572 | /** | |
573 | * pci_doe_submit_task() - Submit a task to be processed by the state machine | |
574 | * | |
575 | * @doe_mb: DOE mailbox capability to submit to | |
576 | * @task: task to be queued | |
577 | * | |
578 | * Submit a DOE task (request/response) to the DOE mailbox to be processed. | |
579 | * Returns upon queueing the task object. If the queue is full this function | |
580 | * will sleep until there is room in the queue. | |
581 | * | |
582 | * task->complete will be called when the state machine is done processing this | |
583 | * task. | |
584 | * | |
92dc899c LW |
585 | * @task must be allocated on the stack. |
586 | * | |
9d24322e JC |
587 | * Excess data will be discarded. |
588 | * | |
589 | * RETURNS: 0 when task has been successfully queued, -ERRNO on error | |
590 | */ | |
0821ff8e LW |
591 | static int pci_doe_submit_task(struct pci_doe_mb *doe_mb, |
592 | struct pci_doe_task *task) | |
9d24322e JC |
593 | { |
594 | if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type)) | |
595 | return -EINVAL; | |
596 | ||
9d24322e JC |
597 | if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) |
598 | return -EIO; | |
599 | ||
600 | task->doe_mb = doe_mb; | |
92dc899c | 601 | INIT_WORK_ONSTACK(&task->work, doe_statemachine_work); |
9d24322e JC |
602 | queue_work(doe_mb->work_queue, &task->work); |
603 | return 0; | |
604 | } | |
62e8b17f LW |
605 | |
606 | /** | |
607 | * pci_doe() - Perform Data Object Exchange | |
608 | * | |
609 | * @doe_mb: DOE Mailbox | |
610 | * @vendor: Vendor ID | |
611 | * @type: Data Object Type | |
612 | * @request: Request payload | |
613 | * @request_sz: Size of request payload (bytes) | |
614 | * @response: Response payload | |
615 | * @response_sz: Size of response payload (bytes) | |
616 | * | |
617 | * Submit @request to @doe_mb and store the @response. | |
618 | * The DOE exchange is performed synchronously and may therefore sleep. | |
619 | * | |
620 | * Payloads are treated as opaque byte streams which are transmitted verbatim, | |
621 | * without byte-swapping. If payloads contain little-endian register values, | |
622 | * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu(). | |
623 | * | |
cedf8d8a LW |
624 | * For convenience, arbitrary payload sizes are allowed even though PCIe r6.0 |
625 | * sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords. The last | |
626 | * (partial) dword is copied with byte granularity and padded with zeroes if | |
627 | * necessary. Callers are thus relieved of using dword-sized bounce buffers. | |
628 | * | |
62e8b17f LW |
629 | * RETURNS: Length of received response or negative errno. |
630 | * Received data in excess of @response_sz is discarded. | |
631 | * The length may be smaller than @response_sz and the caller | |
632 | * is responsible for checking that. | |
633 | */ | |
634 | int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type, | |
635 | const void *request, size_t request_sz, | |
636 | void *response, size_t response_sz) | |
637 | { | |
638 | DECLARE_COMPLETION_ONSTACK(c); | |
639 | struct pci_doe_task task = { | |
640 | .prot.vid = vendor, | |
641 | .prot.type = type, | |
642 | .request_pl = request, | |
643 | .request_pl_sz = request_sz, | |
644 | .response_pl = response, | |
645 | .response_pl_sz = response_sz, | |
646 | .complete = pci_doe_task_complete, | |
647 | .private = &c, | |
648 | }; | |
649 | int rc; | |
650 | ||
651 | rc = pci_doe_submit_task(doe_mb, &task); | |
652 | if (rc) | |
653 | return rc; | |
654 | ||
655 | wait_for_completion(&c); | |
656 | ||
657 | return task.rv; | |
658 | } | |
659 | EXPORT_SYMBOL_GPL(pci_doe); | |
ac048403 LW |
660 | |
661 | /** | |
662 | * pci_find_doe_mailbox() - Find Data Object Exchange mailbox | |
663 | * | |
664 | * @pdev: PCI device | |
665 | * @vendor: Vendor ID | |
666 | * @type: Data Object Type | |
667 | * | |
668 | * Find first DOE mailbox of a PCI device which supports the given protocol. | |
669 | * | |
670 | * RETURNS: Pointer to the DOE mailbox or NULL if none was found. | |
671 | */ | |
672 | struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor, | |
673 | u8 type) | |
674 | { | |
675 | struct pci_doe_mb *doe_mb; | |
676 | unsigned long index; | |
677 | ||
678 | xa_for_each(&pdev->doe_mbs, index, doe_mb) | |
679 | if (pci_doe_supports_prot(doe_mb, vendor, type)) | |
680 | return doe_mb; | |
681 | ||
682 | return NULL; | |
683 | } | |
684 | EXPORT_SYMBOL_GPL(pci_find_doe_mailbox); | |
685 | ||
686 | void pci_doe_init(struct pci_dev *pdev) | |
687 | { | |
688 | struct pci_doe_mb *doe_mb; | |
689 | u16 offset = 0; | |
690 | int rc; | |
691 | ||
692 | xa_init(&pdev->doe_mbs); | |
693 | ||
694 | while ((offset = pci_find_next_ext_capability(pdev, offset, | |
695 | PCI_EXT_CAP_ID_DOE))) { | |
696 | doe_mb = pci_doe_create_mb(pdev, offset); | |
697 | if (IS_ERR(doe_mb)) { | |
698 | pci_err(pdev, "[%x] failed to create mailbox: %ld\n", | |
699 | offset, PTR_ERR(doe_mb)); | |
700 | continue; | |
701 | } | |
702 | ||
703 | rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL); | |
704 | if (rc) { | |
705 | pci_err(pdev, "[%x] failed to insert mailbox: %d\n", | |
706 | offset, rc); | |
707 | pci_doe_destroy_mb(doe_mb); | |
708 | } | |
709 | } | |
710 | } | |
711 | ||
712 | void pci_doe_destroy(struct pci_dev *pdev) | |
713 | { | |
714 | struct pci_doe_mb *doe_mb; | |
715 | unsigned long index; | |
716 | ||
717 | xa_for_each(&pdev->doe_mbs, index, doe_mb) | |
718 | pci_doe_destroy_mb(doe_mb); | |
719 | ||
720 | xa_destroy(&pdev->doe_mbs); | |
721 | } | |
722 | ||
723 | void pci_doe_disconnected(struct pci_dev *pdev) | |
724 | { | |
725 | struct pci_doe_mb *doe_mb; | |
726 | unsigned long index; | |
727 | ||
728 | xa_for_each(&pdev->doe_mbs, index, doe_mb) | |
729 | pci_doe_cancel_tasks(doe_mb); | |
730 | } |