• Guru Das Srinagesh's avatar
    firmware: qcom: scm: Add wait-queue handling logic · 6bf32599
    Guru Das Srinagesh authored
    When the firmware (FW) supports multiple requests per VM, multiple requests
    from the same/different VM can reach the firmware at the same time. Since
    the firmware currently being used has limited resources, it guards them
    with a resource lock and puts requests on a wait-queue internally and
    signals to HLOS that it is doing so. It does this by returning a new return
    value in addition to success or error: SCM_WAITQ_SLEEP. A sleeping SCM call
    can be woken up by an interrupt that the FW raises.
    
      1) SCM_WAITQ_SLEEP:
    
      	When an SCM call receives this return value instead of success
      	or error, FW has placed this call on a wait-queue and has signalled
    	HLOS to put it to non-interruptible sleep.
    
    	Along with this return value, FW also passes to HLOS `wq_ctx` -
    	a unique number (UID) identifying the wait-queue that it has put
    	the call on, internally. This is to help HLOS with its own
    	bookkeeping to wake this sleeping call later.
    
    	Additionally, FW also passes to HLOS `smc_call_ctx` - a UID
    	identifying the SCM call thus being put to sleep. This is also
    	for HLOS' bookkeeping to wake this call up later.
    
    	These two additional values are passed via the a1 and a2
    	registers.
    
    	N.B.: The "ctx" in the above UID names = "context".
    
    The handshake mechanism that HLOS uses to talk to FW about wait-queue
    operations involves two new SMC calls.
    
      1) get_wq_ctx():
    
        	Arguments: 	None
        	Returns:	wq_ctx, flags, more_pending
    
        	Get the wait-queue context, and wake up either one or all of the
        	sleeping SCM calls associated with that wait-queue.
    
        	Additionally, repeat this if there are more wait-queues that are
        	ready to have their requests woken up (`more_pending`).
    
      2) wq_resume(smc_call_ctx):
    
      	Arguments:	smc_call_ctx
    
      	HLOS needs to issue this in response to receiving an
      	IRQ, passing to FW the same smc_call_ctx that FW
      	receives from HLOS via the get_wq_ctx() call.
    
    (The mechanism to wake a SMC call back up is described in detail below)
    
     VM_1                     VM_2                            Firmware
       │                        │                                 │
       │                        │                                 │
       │                        │                                 │
       │                        │                                 │
       │      REQUEST_1         │                                 │
       ├────────────────────────┼─────────────────────────────────┤
       │                        │                                 │
       │                        │                              ┌──┼──┐
       │                        │                              │  │  │
       │                        │     REQUEST_2                │  │  │
       │                        ├──────────────────────────────┼──┤  │
       │                        │                              │  │  │Resource
       │                        │                              │  │  │is busy
       │                        │       {WQ_SLEEP}             │  │  │
       │                        │◄─────────────────────────────┼──┤  │
       │                        │  wq_ctx, smc_call_ctx        │  │  │
       │                        │                              └──┼──┘
       │   REQUEST_1 COMPLETE   │                                 │
       │◄───────────────────────┼─────────────────────────────────┤
       │                        │                                 │
       │                        │         IRQ                     │
       │                        │◄─-------------------------------│
       │                        │                                 │
       │                        │      get_wq_ctx()               │
       │                        ├────────────────────────────────►│
       │                        │                                 │
       │                        │                                 │
       │                        │◄────────────────────────────────┤
       │                        │   wq_ctx, flags, and            │
       │                        │        more_pending             │
       │                        │                                 │
       │                        │                                 │
       │                        │ wq_resume(smc_call_ctx)         │
       │                        ├────────────────────────────────►│
       │                        │                                 │
       │                        │                                 │
       │                        │      REQUEST_2 COMPLETE         │
       │                        │◄────────────────────────────────┤
       │                        │                                 │
       │                        │                                 │
    
    With the exception of get_wq_ctx(), the other SMC call wq_resume() can
    return WQ_SLEEP (these nested rounds of WQ_SLEEP are not shown in the
    above diagram for the sake of simplicity). Therefore, introduce a new
    do-while loop to handle multiple WQ_SLEEP return values for the same
    parent SCM call.
    
    Request Completion in the above diagram refers to either a success
    return value (zero) or error (and not SMC_WAITQ_SLEEP)
    
    Also add the interrupt handler that wakes up a sleeping SCM call.
    Signed-off-by: default avatarGuru Das Srinagesh <quic_gurus@quicinc.com>
    Co-developed-by: default avatarSibi Sankar <quic_sibis@quicinc.com>
    Signed-off-by: default avatarSibi Sankar <quic_sibis@quicinc.com>
    Reviewed-by: default avatarGuru Das Srinagesh <quic_gurus@quicinc.com>
    Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
    Link: https://lore.kernel.org/r/20230113161114.22607-3-quic_sibis@quicinc.com
    6bf32599
qcom_scm.c 39 KB