summaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorAlastair D'Silva <alastair@d-silva.org>2019-06-05 07:15:45 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2019-07-09 23:20:44 -0400
commit73a2b047c81046a7f734a5759ab5fdedbb6968fd (patch)
tree8f5dab40c26fbeab02fe82f6f828bb51b0b166b0 /drivers/misc
parent4ba7f80f42563903b0e26d30175808db7d07e664 (diff)
ocxl: Update for AFU descriptor template version 1.1
The OpenCAPI discovery and configuration specification has been updated and introduces version 1.1 of the AFU descriptor template, with new fields to better define the memory layout of an OpenCAPI adapter. The ocxl driver doesn't do much yet to support LPC memory but as we start seeing (non-LPC) AFU images using the new template, this patch updates the config space parsing code to avoid spitting a warning. Signed-off-by: Alastair D'Silva <alastair@d-silva.org> Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Reviewed-by: Christophe Lombard <clombard@linux.vnet.ibm.com> Acked-by: Andrew Donnellan <ajd@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20190605111545.19762-1-fbarrat@linux.ibm.com
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/ocxl/config.c181
1 files changed, 161 insertions, 20 deletions
diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c
index 5e65acb8e134..c8e19bfb5ef9 100644
--- a/drivers/misc/ocxl/config.c
+++ b/drivers/misc/ocxl/config.c
@@ -20,11 +20,14 @@
20#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28 20#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28
21#define OCXL_DVSEC_TEMPL_MMIO_PP 0x30 21#define OCXL_DVSEC_TEMPL_MMIO_PP 0x30
22#define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38 22#define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38
23#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C 23#define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C
24#define OCXL_DVSEC_TEMPL_WWID 0x40 24#define OCXL_DVSEC_TEMPL_LPC_MEM_START 0x40
25#define OCXL_DVSEC_TEMPL_WWID 0x48
26#define OCXL_DVSEC_TEMPL_LPC_MEM_SZ 0x58
25 27
26#define OCXL_MAX_AFU_PER_FUNCTION 64 28#define OCXL_MAX_AFU_PER_FUNCTION 64
27#define OCXL_TEMPL_LEN 0x58 29#define OCXL_TEMPL_LEN_1_0 0x58
30#define OCXL_TEMPL_LEN_1_1 0x60
28#define OCXL_TEMPL_NAME_LEN 24 31#define OCXL_TEMPL_NAME_LEN 24
29#define OCXL_CFG_TIMEOUT 3 32#define OCXL_CFG_TIMEOUT 3
30 33
@@ -269,34 +272,72 @@ static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn,
269 return 0; 272 return 0;
270} 273}
271 274
275/**
276 * Read the template version from the AFU
277 * dev: the device for the AFU
278 * fn: the AFU offsets
279 * len: outputs the template length
280 * version: outputs the major<<8,minor version
281 *
282 * Returns 0 on success, negative on failure
283 */
284static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn,
285 u16 *len, u16 *version)
286{
287 u32 val32;
288 u8 major, minor;
289 int rc;
290
291 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32);
292 if (rc)
293 return rc;
294
295 *len = EXTRACT_BITS(val32, 16, 31);
296 major = EXTRACT_BITS(val32, 8, 15);
297 minor = EXTRACT_BITS(val32, 0, 7);
298 *version = (major << 8) + minor;
299 return 0;
300}
301
272int ocxl_config_check_afu_index(struct pci_dev *dev, 302int ocxl_config_check_afu_index(struct pci_dev *dev,
273 struct ocxl_fn_config *fn, int afu_idx) 303 struct ocxl_fn_config *fn, int afu_idx)
274{ 304{
275 u32 val; 305 int rc;
276 int rc, templ_major, templ_minor, len; 306 u16 templ_version;
307 u16 len, expected_len;
277 308
278 pci_write_config_byte(dev, 309 pci_write_config_byte(dev,
279 fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX, 310 fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
280 afu_idx); 311 afu_idx);
281 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val); 312
313 rc = read_template_version(dev, fn, &len, &templ_version);
282 if (rc) 314 if (rc)
283 return rc; 315 return rc;
284 316
285 /* AFU index map can have holes */ 317 /* AFU index map can have holes, in which case we read all 0's */
286 if (!val) 318 if (!templ_version && !len)
287 return 0; 319 return 0;
288 320
289 templ_major = EXTRACT_BITS(val, 8, 15);
290 templ_minor = EXTRACT_BITS(val, 0, 7);
291 dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n", 321 dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
292 templ_major, templ_minor); 322 templ_version >> 8, templ_version & 0xFF);
293 323
294 len = EXTRACT_BITS(val, 16, 31); 324 switch (templ_version) {
295 if (len != OCXL_TEMPL_LEN) { 325 case 0x0005: // v0.5 was used prior to the spec approval
296 dev_warn(&dev->dev, 326 case 0x0100:
297 "Unexpected template length in AFU information (%#x)\n", 327 expected_len = OCXL_TEMPL_LEN_1_0;
298 len); 328 break;
329 case 0x0101:
330 expected_len = OCXL_TEMPL_LEN_1_1;
331 break;
332 default:
333 dev_warn(&dev->dev, "Unknown AFU template version %#x\n",
334 templ_version);
335 expected_len = len;
299 } 336 }
337 if (len != expected_len)
338 dev_warn(&dev->dev,
339 "Unexpected template length %#x in AFU information, expected %#x for version %#x\n",
340 len, expected_len, templ_version);
300 return 1; 341 return 1;
301} 342}
302 343
@@ -434,6 +475,102 @@ static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu)
434 return 0; 475 return 0;
435} 476}
436 477
478/**
479 * Populate AFU metadata regarding LPC memory
480 * dev: the device for the AFU
481 * fn: the AFU offsets
482 * afu: the AFU struct to populate the LPC metadata into
483 *
484 * Returns 0 on success, negative on failure
485 */
486static int read_afu_lpc_memory_info(struct pci_dev *dev,
487 struct ocxl_fn_config *fn,
488 struct ocxl_afu_config *afu)
489{
490 int rc;
491 u32 val32;
492 u16 templ_version;
493 u16 templ_len;
494 u64 total_mem_size = 0;
495 u64 lpc_mem_size = 0;
496
497 afu->lpc_mem_offset = 0;
498 afu->lpc_mem_size = 0;
499 afu->special_purpose_mem_offset = 0;
500 afu->special_purpose_mem_size = 0;
501 /*
502 * For AFUs following template v1.0, the LPC memory covers the
503 * total memory. Its size is a power of 2.
504 *
505 * For AFUs with template >= v1.01, the total memory size is
506 * still a power of 2, but it is split in 2 parts:
507 * - the LPC memory, whose size can now be anything
508 * - the remainder memory is a special purpose memory, whose
509 * definition is AFU-dependent. It is not accessible through
510 * the usual commands for LPC memory
511 */
512 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32);
513 if (rc)
514 return rc;
515
516 val32 = EXTRACT_BITS(val32, 0, 7);
517 if (!val32)
518 return 0; /* No LPC memory */
519
520 /*
521 * The configuration space spec allows for a memory size of up
522 * to 2^255 bytes.
523 *
524 * Current generation hardware uses 56-bit physical addresses,
525 * but we won't be able to get near close to that, as we won't
526 * have a hole big enough in the memory map. Let it pass in
527 * the driver for now. We'll get an error from the firmware
528 * when trying to configure something too big.
529 */
530 total_mem_size = 1ull << val32;
531
532 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32);
533 if (rc)
534 return rc;
535
536 afu->lpc_mem_offset = val32;
537
538 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32);
539 if (rc)
540 return rc;
541
542 afu->lpc_mem_offset |= (u64) val32 << 32;
543
544 rc = read_template_version(dev, fn, &templ_len, &templ_version);
545 if (rc)
546 return rc;
547
548 if (templ_version >= 0x0101) {
549 rc = read_afu_info(dev, fn,
550 OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32);
551 if (rc)
552 return rc;
553 lpc_mem_size = val32;
554
555 rc = read_afu_info(dev, fn,
556 OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32);
557 if (rc)
558 return rc;
559 lpc_mem_size |= (u64) val32 << 32;
560 } else {
561 lpc_mem_size = total_mem_size;
562 }
563 afu->lpc_mem_size = lpc_mem_size;
564
565 if (lpc_mem_size < total_mem_size) {
566 afu->special_purpose_mem_offset =
567 afu->lpc_mem_offset + lpc_mem_size;
568 afu->special_purpose_mem_size =
569 total_mem_size - lpc_mem_size;
570 }
571 return 0;
572}
573
437int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, 574int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
438 struct ocxl_afu_config *afu, u8 afu_idx) 575 struct ocxl_afu_config *afu, u8 afu_idx)
439{ 576{
@@ -467,10 +604,9 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
467 if (rc) 604 if (rc)
468 return rc; 605 return rc;
469 606
470 rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32); 607 rc = read_afu_lpc_memory_info(dev, fn, afu);
471 if (rc) 608 if (rc)
472 return rc; 609 return rc;
473 afu->log_mem_size = EXTRACT_BITS(val32, 0, 7);
474 610
475 rc = read_afu_control(dev, afu); 611 rc = read_afu_control(dev, afu);
476 if (rc) 612 if (rc)
@@ -487,7 +623,12 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
487 dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar); 623 dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
488 dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset); 624 dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
489 dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride); 625 dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride);
490 dev_dbg(&dev->dev, " mem size (log) = %hhu\n", afu->log_mem_size); 626 dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset);
627 dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size);
628 dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n",
629 afu->special_purpose_mem_offset);
630 dev_dbg(&dev->dev, " special purpose mem size = %#llx\n",
631 afu->special_purpose_mem_size);
491 dev_dbg(&dev->dev, " pasid supported (log) = %u\n", 632 dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
492 afu->pasid_supported_log); 633 afu->pasid_supported_log);
493 dev_dbg(&dev->dev, " actag supported = %u\n", 634 dev_dbg(&dev->dev, " actag supported = %u\n",