firmware: arm_ffa: Fix handling of fragmented memory descriptors
authorMarc Bonnici <marc.bonnici@arm.com>
Tue, 26 Apr 2022 12:12:19 +0000 (13:12 +0100)
committerSudeep Holla <sudeep.holla@arm.com>
Wed, 27 Apr 2022 07:55:29 +0000 (08:55 +0100)
Fix the handling of MEM_FRAG_TX/RX SMCs when the full memory descriptor
does not fit in a single innovation of a memory sharing request.

The current implementation expects a FFA_MEM_SHARE/FFA_MEM_LEND
call to always receive a FFA_SUCCESS response, however in the
case where a full descriptor does not fit inside the partitions
TX buffer, the call can instead complete with a FFA_MEM_FRAG_RX SMC
to request the next part of the descriptor to be transmitted.

Similarly a FFA_MEM_FRAG_TX call currently only expects
FFA_MEM_FRAG_RX as a response, however once the full descriptor
has been transmitted the FFA_SUCCESS ABI will be used to indicate
successful transmission.

Update the existing code to match the expected behaviour.

Link: https://lore.kernel.org/r/20220426121219.1801601-1-marc.bonnici@arm.com
Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_ffa/driver.c

index 14f900047ac0ceb3c7792075f3beb6a8f3f448de..ccccecae615fcef81034a327ec7f5e7a5ebd0f02 100644 (file)
@@ -398,11 +398,15 @@ static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz,
        if (ret.a0 == FFA_ERROR)
                return ffa_to_linux_errno((int)ret.a2);
 
-       if (ret.a0 != FFA_SUCCESS)
+       if (ret.a0 == FFA_SUCCESS) {
+               if (handle)
+                       *handle = PACK_HANDLE(ret.a2, ret.a3);
+       } else if (ret.a0 == FFA_MEM_FRAG_RX) {
+               if (handle)
+                       *handle = PACK_HANDLE(ret.a1, ret.a2);
+       } else {
                return -EOPNOTSUPP;
-
-       if (handle)
-               *handle = PACK_HANDLE(ret.a2, ret.a3);
+       }
 
        return frag_len;
 }
@@ -426,10 +430,12 @@ static int ffa_mem_next_frag(u64 handle, u32 frag_len)
        if (ret.a0 == FFA_ERROR)
                return ffa_to_linux_errno((int)ret.a2);
 
-       if (ret.a0 != FFA_MEM_FRAG_RX)
-               return -EOPNOTSUPP;
+       if (ret.a0 == FFA_MEM_FRAG_RX)
+               return ret.a3;
+       else if (ret.a0 == FFA_SUCCESS)
+               return 0;
 
-       return ret.a3;
+       return -EOPNOTSUPP;
 }
 
 static int