Skip to content

Commit 73a2b04

Browse files
deecempe
authored andcommitted
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
1 parent 4ba7f80 commit 73a2b04

File tree

2 files changed

+165
-21
lines changed

2 files changed

+165
-21
lines changed

drivers/misc/ocxl/config.c

Lines changed: 161 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28
2121
#define OCXL_DVSEC_TEMPL_MMIO_PP 0x30
2222
#define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38
23-
#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C
24-
#define OCXL_DVSEC_TEMPL_WWID 0x40
23+
#define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C
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
2527

2628
#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
2831
#define OCXL_TEMPL_NAME_LEN 24
2932
#define OCXL_CFG_TIMEOUT 3
3033

@@ -269,34 +272,72 @@ static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn,
269272
return 0;
270273
}
271274

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+
*/
284+
static 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+
272302
int ocxl_config_check_afu_index(struct pci_dev *dev,
273303
struct ocxl_fn_config *fn, int afu_idx)
274304
{
275-
u32 val;
276-
int rc, templ_major, templ_minor, len;
305+
int rc;
306+
u16 templ_version;
307+
u16 len, expected_len;
277308

278309
pci_write_config_byte(dev,
279310
fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
280311
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);
282314
if (rc)
283315
return rc;
284316

285-
/* AFU index map can have holes */
286-
if (!val)
317+
/* AFU index map can have holes, in which case we read all 0's */
318+
if (!templ_version && !len)
287319
return 0;
288320

289-
templ_major = EXTRACT_BITS(val, 8, 15);
290-
templ_minor = EXTRACT_BITS(val, 0, 7);
291321
dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
292-
templ_major, templ_minor);
293-
294-
len = EXTRACT_BITS(val, 16, 31);
295-
if (len != OCXL_TEMPL_LEN) {
296-
dev_warn(&dev->dev,
297-
"Unexpected template length in AFU information (%#x)\n",
298-
len);
322+
templ_version >> 8, templ_version & 0xFF);
323+
324+
switch (templ_version) {
325+
case 0x0005: // v0.5 was used prior to the spec approval
326+
case 0x0100:
327+
expected_len = OCXL_TEMPL_LEN_1_0;
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;
299336
}
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);
300341
return 1;
301342
}
302343

@@ -434,6 +475,102 @@ static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu)
434475
return 0;
435476
}
436477

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+
*/
486+
static 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+
437574
int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
438575
struct ocxl_afu_config *afu, u8 afu_idx)
439576
{
@@ -467,10 +604,9 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
467604
if (rc)
468605
return rc;
469606

470-
rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32);
607+
rc = read_afu_lpc_memory_info(dev, fn, afu);
471608
if (rc)
472609
return rc;
473-
afu->log_mem_size = EXTRACT_BITS(val32, 0, 7);
474610

475611
rc = read_afu_control(dev, afu);
476612
if (rc)
@@ -487,7 +623,12 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
487623
dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
488624
dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
489625
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);
491632
dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
492633
afu->pasid_supported_log);
493634
dev_dbg(&dev->dev, " actag supported = %u\n",

include/misc/ocxl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ struct ocxl_afu_config {
3232
u8 pp_mmio_bar; /* per-process MMIO area */
3333
u64 pp_mmio_offset;
3434
u32 pp_mmio_stride;
35-
u8 log_mem_size;
35+
u64 lpc_mem_offset;
36+
u64 lpc_mem_size;
37+
u64 special_purpose_mem_offset;
38+
u64 special_purpose_mem_size;
3639
u8 pasid_supported_log;
3740
u16 actag_supported;
3841
};

0 commit comments

Comments
 (0)