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+
272302int 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+
437574int 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" ,
0 commit comments