Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor

FF-A v1.2 introduced 16 byte IMPLEMENTATION DEFINED value in the endpoint
memory access descriptor to allow any sender could to specify an its any
custom value for each receiver. Also this value must be specified by the
receiver when retrieving the memory region. The sender must ensure it
informs the receiver of this value via an IMPLEMENTATION DEFINED mechanism
such as a partition message.

So the FF-A driver can use the message interfaces to communicate the value
and set the same in the ffa_mem_region_attributes structures when using
the memory interfaces.

The driver ensure that the size of the endpoint memory access descriptors
is set correctly based on the FF-A version.

Fixes: 9fac08d9d985 ("firmware: arm_ffa: Upgrade FF-A version to v1.2 in the driver")
Reported-by: Lixiang Mao <liximao@qti.qualcomm.com>
Tested-by: Lixiang Mao <liximao@qti.qualcomm.com>
Message-Id: <20250923150927.1218364-1-sudeep.holla@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

+46 -12
+27 -10
drivers/firmware/arm_ffa/driver.c
··· 649 649 return FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | FFA_MEM_INNER_SHAREABLE; 650 650 } 651 651 652 + static void ffa_emad_impdef_value_init(u32 version, void *dst, void *src) 653 + { 654 + struct ffa_mem_region_attributes *ep_mem_access; 655 + 656 + if (FFA_EMAD_HAS_IMPDEF_FIELD(version)) 657 + memcpy(dst, src, sizeof(ep_mem_access->impdef_val)); 658 + } 659 + 660 + static void 661 + ffa_mem_region_additional_setup(u32 version, struct ffa_mem_region *mem_region) 662 + { 663 + if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version)) { 664 + mem_region->ep_mem_size = 0; 665 + } else { 666 + mem_region->ep_mem_size = ffa_emad_size_get(version); 667 + mem_region->ep_mem_offset = sizeof(*mem_region); 668 + memset(mem_region->reserved, 0, 12); 669 + } 670 + } 671 + 652 672 static int 653 673 ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, 654 674 struct ffa_mem_ops_args *args) ··· 687 667 mem_region->flags = args->flags; 688 668 mem_region->sender_id = drv_info->vm_id; 689 669 mem_region->attributes = ffa_memory_attributes_get(func_id); 690 - ep_mem_access = buffer + 691 - ffa_mem_desc_offset(buffer, 0, drv_info->version); 692 670 composite_offset = ffa_mem_desc_offset(buffer, args->nattrs, 693 671 drv_info->version); 694 672 695 - for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { 673 + for (idx = 0; idx < args->nattrs; idx++) { 674 + ep_mem_access = buffer + 675 + ffa_mem_desc_offset(buffer, idx, drv_info->version); 696 676 ep_mem_access->receiver = args->attrs[idx].receiver; 697 677 ep_mem_access->attrs = args->attrs[idx].attrs; 698 678 ep_mem_access->composite_off = composite_offset; 699 679 ep_mem_access->flag = 0; 700 680 ep_mem_access->reserved = 0; 681 + ffa_emad_impdef_value_init(drv_info->version, 682 + ep_mem_access->impdef_val, 683 + args->attrs[idx].impdef_val); 701 684 } 702 685 mem_region->handle = 0; 703 686 mem_region->ep_count = args->nattrs; 704 - if (drv_info->version <= FFA_VERSION_1_0) { 705 - mem_region->ep_mem_size = 0; 706 - } else { 707 - mem_region->ep_mem_size = sizeof(*ep_mem_access); 708 - mem_region->ep_mem_offset = sizeof(*mem_region); 709 - memset(mem_region->reserved, 0, 12); 710 - } 687 + ffa_mem_region_additional_setup(drv_info->version, mem_region); 711 688 712 689 composite = buffer + composite_offset; 713 690 composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
+19 -2
include/linux/arm_ffa.h
··· 338 338 * an `struct ffa_mem_region_addr_range`. 339 339 */ 340 340 u32 composite_off; 341 + u8 impdef_val[16]; 341 342 u64 reserved; 342 343 }; 343 344 ··· 418 417 #define CONSTITUENTS_OFFSET(x) \ 419 418 (offsetof(struct ffa_composite_mem_region, constituents[x])) 420 419 420 + #define FFA_EMAD_HAS_IMPDEF_FIELD(version) ((version) >= FFA_VERSION_1_2) 421 + #define FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version) ((version) > FFA_VERSION_1_0) 422 + 423 + static inline u32 ffa_emad_size_get(u32 ffa_version) 424 + { 425 + u32 sz; 426 + struct ffa_mem_region_attributes *ep_mem_access; 427 + 428 + if (FFA_EMAD_HAS_IMPDEF_FIELD(ffa_version)) 429 + sz = sizeof(*ep_mem_access); 430 + else 431 + sz = sizeof(*ep_mem_access) - sizeof(ep_mem_access->impdef_val); 432 + 433 + return sz; 434 + } 435 + 421 436 static inline u32 422 437 ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version) 423 438 { 424 - u32 offset = count * sizeof(struct ffa_mem_region_attributes); 439 + u32 offset = count * ffa_emad_size_get(ffa_version); 425 440 /* 426 441 * Earlier to v1.1, the endpoint memory descriptor array started at 427 442 * offset 32(i.e. offset of ep_mem_offset in the current structure) 428 443 */ 429 - if (ffa_version <= FFA_VERSION_1_0) 444 + if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version)) 430 445 offset += offsetof(struct ffa_mem_region, ep_mem_offset); 431 446 else 432 447 offset += sizeof(struct ffa_mem_region);