1b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie/*
2b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * Copyright (C) 2017 The Android Open Source Project
3b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie *
4b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * Licensed under the Apache License, Version 2.0 (the "License");
5b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * you may not use this file except in compliance with the License.
6b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * You may obtain a copy of the License at
7b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie *
8b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie *      http://www.apache.org/licenses/LICENSE-2.0
9b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie *
10b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * Unless required by applicable law or agreed to in writing, software
11b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * distributed under the License is distributed on an "AS IS" BASIS,
12b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * See the License for the specific language governing permissions and
14b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie * limitations under the License.
15b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie */
16b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
17b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie#include "chre/platform/slpi/smr_helper.h"
18b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
19b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie#include <inttypes.h>
20b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
21b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie#include "chre/platform/assert.h"
22b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie#include "chre/platform/log.h"
238d0e0251dc82dec80d458dada7d5345c1967b556Arthur Ishiguro#include "chre/platform/slpi/power_control_util.h"
24b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie#include "chre/util/lock_guard.h"
25b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
26b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddienamespace chre {
27b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
28b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddiesmr_err SmrHelper::releaseSync(smr_client_hndl clientHandle,
29b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                               Nanoseconds timeout) {
30b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // smr_client_release is synchronous for SMR services in the current
31b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // implementation, so we can't hold the lock while calling it otherwise we'll
32b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // deadlock in the callback.
33b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  {
34b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    LockGuard<Mutex> lock(mMutex);
35b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    CHRE_ASSERT(!mWaiting);
36b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mWaiting = true;
37b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  }
38b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
39b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  smr_err result = smr_client_release(
40b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      clientHandle, SmrHelper::smrReleaseCb, this);
41b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  if (result == SMR_NO_ERR) {
42b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    LockGuard<Mutex> lock(mMutex);
43b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    bool waitSuccess = true;
44b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    while (mWaiting && waitSuccess) {
45b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      waitSuccess = mCond.wait_for(mMutex, timeout);
46b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    }
47b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
48b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    if (!waitSuccess) {
49b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      LOGE("Releasing SMR client timed out");
50b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      result = SMR_TIMEOUT_ERR;
51b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      mWaiting = false;
52b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    }
53b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  }
54b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
55b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  return result;
56b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}
57b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
58e0653a607542819b492d789952159a528c9a5e4eArthur Ishigurosmr_err SmrHelper::waitForService(qmi_idl_service_object_type serviceObj,
59e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                  Microseconds timeout) {
60e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  // smr_client_check_ext is synchronous if the service already exists,
61e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  // so don't hold the lock while calling to prevent deadlock in the callback.
62e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  {
63e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    LockGuard<Mutex> lock(mMutex);
64e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    CHRE_ASSERT(!mWaiting);
65e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    mWaiting = true;
66e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  }
67e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro
68e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  smr_err result = smr_client_check_ext(serviceObj, SMR_CLIENT_INSTANCE_ANY,
69e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                        timeout.getMicroseconds(),
70e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                        SmrHelper::smrWaitForServiceCb, this);
71e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  if (result == SMR_NO_ERR) {
72e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    LockGuard<Mutex> lock(mMutex);
73e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    while (mWaiting) {
74e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro      mCond.wait(mMutex);
75e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    }
76e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro
77e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    if (mServiceTimedOut) {
78e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro      LOGE("Wait for SMR service timed out");
79e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro      result = SMR_TIMEOUT_ERR;
80e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro      mServiceTimedOut = false;
81e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro    }
82e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  }
83e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro
84e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  return result;
85e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro}
86e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro
87b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddiebool SmrHelper::sendReqSyncUntyped(
88b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    smr_client_hndl client_handle, unsigned int msg_id,
89b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    void *req_c_struct, unsigned int req_c_struct_len,
90b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    void *resp_c_struct, unsigned int resp_c_struct_len,
91b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    Nanoseconds timeout, smr_err *result) {
92b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  LockGuard<Mutex> lock(mMutex);
93b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  CHRE_ASSERT(!mWaiting);
94b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  bool waitSuccess = true;
95b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
968d0e0251dc82dec80d458dada7d5345c1967b556Arthur Ishiguro  // Force big image since smr_client_send_req is not supported in micro-image
978d0e0251dc82dec80d458dada7d5345c1967b556Arthur Ishiguro  slpiForceBigImage();
988d0e0251dc82dec80d458dada7d5345c1967b556Arthur Ishiguro
99b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // Note that null txn_handle means we can't abandon the transaction, but it's
100b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // only supported for QMI (non-SMR) services, and we don't expect that anyway.
101b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  // SMR itself does not support canceling transactions made to SMR services.
102b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  *result = smr_client_send_req(
103b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      client_handle, msg_id, req_c_struct, req_c_struct_len, resp_c_struct,
104b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      resp_c_struct_len, SmrHelper::smrRespCb, this, nullptr /* txn_handle */);
105b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  if (*result != SMR_NO_ERR) {
106b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    LOGE("Failed to send request (msg_id 0x%02x): %d", msg_id, *result);
107b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  } else {
108b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mWaiting = true;
109b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mPendingRespBuf = resp_c_struct;
110b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
111b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    while (mWaiting && waitSuccess) {
112b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      waitSuccess = mCond.wait_for(mMutex, timeout);
113b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    }
114b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
115b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    if (waitSuccess) {
116b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      *result = mTranspErr;
117b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    } else {
118b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      LOGE("SMR request for msg_id 0x%02x timed out after %" PRIu64 " ms",
119b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie           msg_id, Milliseconds(timeout).getMilliseconds());
120b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      *result = SMR_TIMEOUT_ERR;
121b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie      mWaiting = false;
122b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    }
123b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mPendingRespBuf = nullptr;
124b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  }
125b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
126b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  return waitSuccess;
127b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}
128b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
129b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddievoid SmrHelper::handleResp(smr_client_hndl client_handle, unsigned int msg_id,
130b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                           void *resp_c_struct, unsigned int resp_c_struct_len,
131b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                           smr_err transp_err) {
132b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  LockGuard<Mutex> lock(mMutex);
133b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
134b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  if (!mWaiting) {
135b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    LOGE("Got SMR response when none pending!");
136b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  } else if (mPendingRespBuf != resp_c_struct) {
137b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    LOGE("Got SMR response with unexpected buffer, msg_id 0x%02x: %p vs. %p",
138b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie         msg_id, mPendingRespBuf, resp_c_struct);
139b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  } else {
140b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    // SMR will handle copying the response into the buffer passed in to
141b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    // smr_client_send_req(), so we just need to unblock the waiting thread
142b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mTranspErr = transp_err;
143b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mWaiting = false;
144b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie    mCond.notify_one();
145b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  }
146b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}
147b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
148b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddievoid SmrHelper::smrReleaseCb(void *release_cb_data) {
149b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  SmrHelper *obj = static_cast<SmrHelper *>(release_cb_data);
150b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  LockGuard<Mutex> lock(obj->mMutex);
151b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  obj->mWaiting = false;
152b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  obj->mCond.notify_one();
153b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}
154b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
155b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddievoid SmrHelper::smrRespCb(smr_client_hndl client_handle, unsigned int msg_id,
156b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                          void *resp_c_struct, unsigned int resp_c_struct_len,
157b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                          void *resp_cb_data, smr_err transp_err) {
158b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  SmrHelper *obj = static_cast<SmrHelper *>(resp_cb_data);
159b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie  obj->handleResp(client_handle, msg_id, resp_c_struct, resp_c_struct_len,
160b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie                  transp_err);
161b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}
162b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie
163e0653a607542819b492d789952159a528c9a5e4eArthur Ishigurovoid SmrHelper::smrWaitForServiceCb(qmi_idl_service_object_type /* service_obj */,
164e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                    qmi_service_instance /* instance_id */,
165e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                    bool timeout_expired,
166e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro                                    void *wait_for_service_cb_data) {
167e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  SmrHelper *obj = static_cast<SmrHelper *>(wait_for_service_cb_data);
168e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  LockGuard<Mutex> lock(obj->mMutex);
169e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  obj->mServiceTimedOut = timeout_expired;
170e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  obj->mWaiting = false;
171e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro  obj->mCond.notify_one();
172e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro}
173e0653a607542819b492d789952159a528c9a5e4eArthur Ishiguro
174b9d199936165f42ac7e7eabac1bdb4968d938f4fBrian Duddie}  // namespace chre
175