Skip to content

Commit f4cb028

Browse files
committed
Merge tag 'ffa-fix-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes
Arm FF-A fix for v6.18 The FF-A driver was updated to support specification version 1.2 but omitted support for the 16-byte implementation-defined (IMPDEF) field introduced in FF-A v1.2 within the Endpoint Memory Access Descriptor (EMAD). This omission breaks all memory interfaces. This change updates the EMAD sizing and offset logic to correctly handle the FF-A v1.2 layout while preserving backward compatibility with older versions. * tag 'ffa-fix-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 1d4e7d9 + 11fb1a8 commit f4cb028

2 files changed

Lines changed: 46 additions & 12 deletions

File tree

drivers/firmware/arm_ffa/driver.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,26 @@ static u16 ffa_memory_attributes_get(u32 func_id)
649649
return FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | FFA_MEM_INNER_SHAREABLE;
650650
}
651651

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+
652672
static int
653673
ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
654674
struct ffa_mem_ops_args *args)
@@ -667,27 +687,24 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
667687
mem_region->flags = args->flags;
668688
mem_region->sender_id = drv_info->vm_id;
669689
mem_region->attributes = ffa_memory_attributes_get(func_id);
670-
ep_mem_access = buffer +
671-
ffa_mem_desc_offset(buffer, 0, drv_info->version);
672690
composite_offset = ffa_mem_desc_offset(buffer, args->nattrs,
673691
drv_info->version);
674692

675-
for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) {
693+
for (idx = 0; idx < args->nattrs; idx++) {
694+
ep_mem_access = buffer +
695+
ffa_mem_desc_offset(buffer, idx, drv_info->version);
676696
ep_mem_access->receiver = args->attrs[idx].receiver;
677697
ep_mem_access->attrs = args->attrs[idx].attrs;
678698
ep_mem_access->composite_off = composite_offset;
679699
ep_mem_access->flag = 0;
680700
ep_mem_access->reserved = 0;
701+
ffa_emad_impdef_value_init(drv_info->version,
702+
ep_mem_access->impdef_val,
703+
args->attrs[idx].impdef_val);
681704
}
682705
mem_region->handle = 0;
683706
mem_region->ep_count = args->nattrs;
684-
if (drv_info->version <= FFA_VERSION_1_0) {
685-
mem_region->ep_mem_size = 0;
686-
} else {
687-
mem_region->ep_mem_size = sizeof(*ep_mem_access);
688-
mem_region->ep_mem_offset = sizeof(*mem_region);
689-
memset(mem_region->reserved, 0, 12);
690-
}
707+
ffa_mem_region_additional_setup(drv_info->version, mem_region);
691708

692709
composite = buffer + composite_offset;
693710
composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);

include/linux/arm_ffa.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ struct ffa_mem_region_attributes {
338338
* an `struct ffa_mem_region_addr_range`.
339339
*/
340340
u32 composite_off;
341+
u8 impdef_val[16];
341342
u64 reserved;
342343
};
343344

@@ -417,15 +418,31 @@ struct ffa_mem_region {
417418
#define CONSTITUENTS_OFFSET(x) \
418419
(offsetof(struct ffa_composite_mem_region, constituents[x]))
419420

421+
#define FFA_EMAD_HAS_IMPDEF_FIELD(version) ((version) >= FFA_VERSION_1_2)
422+
#define FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version) ((version) > FFA_VERSION_1_0)
423+
424+
static inline u32 ffa_emad_size_get(u32 ffa_version)
425+
{
426+
u32 sz;
427+
struct ffa_mem_region_attributes *ep_mem_access;
428+
429+
if (FFA_EMAD_HAS_IMPDEF_FIELD(ffa_version))
430+
sz = sizeof(*ep_mem_access);
431+
else
432+
sz = sizeof(*ep_mem_access) - sizeof(ep_mem_access->impdef_val);
433+
434+
return sz;
435+
}
436+
420437
static inline u32
421438
ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
422439
{
423-
u32 offset = count * sizeof(struct ffa_mem_region_attributes);
440+
u32 offset = count * ffa_emad_size_get(ffa_version);
424441
/*
425442
* Earlier to v1.1, the endpoint memory descriptor array started at
426443
* offset 32(i.e. offset of ep_mem_offset in the current structure)
427444
*/
428-
if (ffa_version <= FFA_VERSION_1_0)
445+
if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version))
429446
offset += offsetof(struct ffa_mem_region, ep_mem_offset);
430447
else
431448
offset += sizeof(struct ffa_mem_region);

0 commit comments

Comments
 (0)