Merge "soc: qcom: glink: Validate ctx before using"

This commit is contained in:
Linux Build Service Account 2016-09-02 13:52:25 -07:00 committed by Gerrit - the friendly Code Review server
commit d95f7bea18

View file

@ -30,6 +30,7 @@
#include "glink_private.h" #include "glink_private.h"
#include "glink_xprt_if.h" #include "glink_xprt_if.h"
#define GLINK_CTX_CANARY 0x58544324 /* "$CTX" */
/* Number of internal IPC Logging log pages */ /* Number of internal IPC Logging log pages */
#define NUM_LOG_PAGES 10 #define NUM_LOG_PAGES 10
#define GLINK_PM_QOS_HOLDOFF_MS 10 #define GLINK_PM_QOS_HOLDOFF_MS 10
@ -38,6 +39,8 @@
#define GLINK_QOS_DEF_MTU 2048 #define GLINK_QOS_DEF_MTU 2048
#define GLINK_KTHREAD_PRIO 1 #define GLINK_KTHREAD_PRIO 1
static rwlock_t magic_lock;
/** /**
* struct glink_qos_priority_bin - Packet Scheduler's priority bucket * struct glink_qos_priority_bin - Packet Scheduler's priority bucket
* @max_rate_kBps: Maximum rate supported by the priority bucket. * @max_rate_kBps: Maximum rate supported by the priority bucket.
@ -308,6 +311,7 @@ struct channel_ctx {
unsigned long req_rate_kBps; unsigned long req_rate_kBps;
uint32_t tx_intent_cnt; uint32_t tx_intent_cnt;
uint32_t tx_cnt; uint32_t tx_cnt;
uint32_t magic_number;
}; };
static struct glink_core_if core_impl; static struct glink_core_if core_impl;
@ -436,6 +440,37 @@ static void glink_core_deinit_xprt_qos_cfg(
#define GLINK_GET_CH_TX_STATE(ctx) \ #define GLINK_GET_CH_TX_STATE(ctx) \
((ctx)->tx_intent_cnt || (ctx)->tx_cnt) ((ctx)->tx_intent_cnt || (ctx)->tx_cnt)
static int glink_get_ch_ctx(struct channel_ctx *ctx)
{
unsigned long flags;
if (!ctx)
return -EINVAL;
read_lock_irqsave(&magic_lock, flags);
if (ctx->magic_number != GLINK_CTX_CANARY) {
read_unlock_irqrestore(&magic_lock, flags);
return -EINVAL;
}
rwref_get(&ctx->ch_state_lhb2);
read_unlock_irqrestore(&magic_lock, flags);
return 0;
}
static int glink_put_ch_ctx(struct channel_ctx *ctx, bool update_magic)
{
unsigned long flags;
if (!update_magic) {
rwref_put(&ctx->ch_state_lhb2);
return 0;
}
write_lock_irqsave(&magic_lock, flags);
ctx->magic_number = 0;
rwref_put(&ctx->ch_state_lhb2);
write_unlock_irqrestore(&magic_lock, flags);
return 0;
}
/** /**
* glink_ssr() - Clean up locally for SSR by simulating remote close * glink_ssr() - Clean up locally for SSR by simulating remote close
* @subsystem: The name of the subsystem being restarted * @subsystem: The name of the subsystem being restarted
@ -2583,7 +2618,7 @@ void *glink_open(const struct glink_open_config *cfg)
GLINK_INFO_CH(ctx, "%s: Created channel, sent OPEN command. ctx %p\n", GLINK_INFO_CH(ctx, "%s: Created channel, sent OPEN command. ctx %p\n",
__func__, ctx); __func__, ctx);
ctx->magic_number = GLINK_CTX_CANARY;
return ctx; return ctx;
} }
EXPORT_SYMBOL(glink_open); EXPORT_SYMBOL(glink_open);
@ -2681,15 +2716,19 @@ int glink_close(void *handle)
unsigned long flags; unsigned long flags;
bool is_empty = false; bool is_empty = false;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx); GLINK_INFO_CH(ctx, "%s: Closing channel, ctx: %p\n", __func__, ctx);
if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) if (ctx->local_open_state == GLINK_CHANNEL_CLOSED) {
glink_put_ch_ctx(ctx, false);
return 0; return 0;
}
if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) { if (ctx->local_open_state == GLINK_CHANNEL_CLOSING) {
/* close already pending */ /* close already pending */
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
@ -2754,6 +2793,7 @@ relock: xprt_ctx = ctx->transport_ptr;
rwref_put(&ctx->ch_state_lhb2); rwref_put(&ctx->ch_state_lhb2);
rwref_read_put(&xprt_ctx->xprt_state_lhb0); rwref_read_put(&xprt_ctx->xprt_state_lhb0);
glink_put_ch_ctx(ctx, true);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_close); EXPORT_SYMBOL(glink_close);
@ -2812,29 +2852,30 @@ static int glink_tx_common(void *handle, void *pkt_priv,
if (!size) if (!size)
return -EINVAL; return -EINVAL;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
rwref_read_get_atomic(&ctx->ch_state_lhb2, is_atomic); rwref_read_get_atomic(&ctx->ch_state_lhb2, is_atomic);
if (!(vbuf_provider || pbuf_provider)) { if (!(vbuf_provider || pbuf_provider)) {
rwref_read_put(&ctx->ch_state_lhb2); ret = -EINVAL;
return -EINVAL; goto glink_tx_common_err;
} }
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
rwref_read_put(&ctx->ch_state_lhb2); ret = -EBUSY;
return -EBUSY; goto glink_tx_common_err;
} }
if (size > GLINK_MAX_PKT_SIZE) { if (size > GLINK_MAX_PKT_SIZE) {
rwref_read_put(&ctx->ch_state_lhb2); ret = -EINVAL;
return -EINVAL; goto glink_tx_common_err;
} }
if (unlikely(tx_flags & GLINK_TX_TRACER_PKT)) { if (unlikely(tx_flags & GLINK_TX_TRACER_PKT)) {
if (!(ctx->transport_ptr->capabilities & GCAP_TRACER_PKT)) { if (!(ctx->transport_ptr->capabilities & GCAP_TRACER_PKT)) {
rwref_read_put(&ctx->ch_state_lhb2); ret = -EOPNOTSUPP;
return -EOPNOTSUPP; goto glink_tx_common_err;
} }
tracer_pkt_log_event(data, GLINK_CORE_TX); tracer_pkt_log_event(data, GLINK_CORE_TX);
} }
@ -2846,16 +2887,16 @@ static int glink_tx_common(void *handle, void *pkt_priv,
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: R[%u]:%zu Intent not present for lcid\n", "%s: R[%u]:%zu Intent not present for lcid\n",
__func__, riid, size); __func__, riid, size);
rwref_read_put(&ctx->ch_state_lhb2); ret = -EAGAIN;
return -EAGAIN; goto glink_tx_common_err;
} }
if (is_atomic && !(ctx->transport_ptr->capabilities & if (is_atomic && !(ctx->transport_ptr->capabilities &
GCAP_AUTO_QUEUE_RX_INT)) { GCAP_AUTO_QUEUE_RX_INT)) {
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: Cannot request intent in atomic context\n", "%s: Cannot request intent in atomic context\n",
__func__); __func__);
rwref_read_put(&ctx->ch_state_lhb2); ret = -EINVAL;
return -EINVAL; goto glink_tx_common_err;
} }
/* request intent of correct size */ /* request intent of correct size */
@ -2865,20 +2906,18 @@ static int glink_tx_common(void *handle, void *pkt_priv,
if (ret) { if (ret) {
GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n", GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n",
__func__, ret); __func__, ret);
rwref_read_put(&ctx->ch_state_lhb2); goto glink_tx_common_err;
return ret;
} }
while (ch_pop_remote_rx_intent(ctx, size, &riid, while (ch_pop_remote_rx_intent(ctx, size, &riid,
&intent_size, &cookie)) { &intent_size, &cookie)) {
rwref_get(&ctx->ch_state_lhb2);
rwref_read_put(&ctx->ch_state_lhb2); rwref_read_put(&ctx->ch_state_lhb2);
if (is_atomic) { if (is_atomic) {
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s Intent of size %zu not ready\n", "%s Intent of size %zu not ready\n",
__func__, size); __func__, size);
rwref_put(&ctx->ch_state_lhb2); ret = -EAGAIN;
return -EAGAIN; goto glink_tx_common_err_2;
} }
if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN
@ -2886,8 +2925,8 @@ static int glink_tx_common(void *handle, void *pkt_priv,
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: Channel closed while waiting for intent\n", "%s: Channel closed while waiting for intent\n",
__func__); __func__);
rwref_put(&ctx->ch_state_lhb2); ret = -EBUSY;
return -EBUSY; goto glink_tx_common_err_2;
} }
/* wait for the remote intent req ack */ /* wait for the remote intent req ack */
@ -2897,8 +2936,8 @@ static int glink_tx_common(void *handle, void *pkt_priv,
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: Intent request ack with size: %zu not granted for lcid\n", "%s: Intent request ack with size: %zu not granted for lcid\n",
__func__, size); __func__, size);
rwref_put(&ctx->ch_state_lhb2); ret = -ETIMEDOUT;
return -ETIMEDOUT; goto glink_tx_common_err_2;
} }
if (!ctx->int_req_ack) { if (!ctx->int_req_ack) {
@ -2906,8 +2945,8 @@ static int glink_tx_common(void *handle, void *pkt_priv,
"%s: Intent Request with size: %zu %s", "%s: Intent Request with size: %zu %s",
__func__, size, __func__, size,
"not granted for lcid\n"); "not granted for lcid\n");
rwref_put(&ctx->ch_state_lhb2); ret = -EAGAIN;
return -EAGAIN; goto glink_tx_common_err_2;
} }
/* wait for the rx_intent from remote side */ /* wait for the rx_intent from remote side */
@ -2917,13 +2956,12 @@ static int glink_tx_common(void *handle, void *pkt_priv,
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: Intent request with size: %zu not granted for lcid\n", "%s: Intent request with size: %zu not granted for lcid\n",
__func__, size); __func__, size);
rwref_put(&ctx->ch_state_lhb2); ret = -ETIMEDOUT;
return -ETIMEDOUT; goto glink_tx_common_err_2;
} }
reinit_completion(&ctx->int_req_complete); reinit_completion(&ctx->int_req_complete);
rwref_read_get(&ctx->ch_state_lhb2); rwref_read_get(&ctx->ch_state_lhb2);
rwref_put(&ctx->ch_state_lhb2);
} }
} }
@ -2943,8 +2981,8 @@ static int glink_tx_common(void *handle, void *pkt_priv,
if (!tx_info) { if (!tx_info) {
GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__); GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__);
ch_push_remote_rx_intent(ctx, intent_size, riid, cookie); ch_push_remote_rx_intent(ctx, intent_size, riid, cookie);
rwref_read_put(&ctx->ch_state_lhb2); ret = -ENOMEM;
return -ENOMEM; goto glink_tx_common_err;
} }
rwref_lock_init(&tx_info->pkt_ref, glink_tx_pkt_release); rwref_lock_init(&tx_info->pkt_ref, glink_tx_pkt_release);
INIT_LIST_HEAD(&tx_info->list_done); INIT_LIST_HEAD(&tx_info->list_done);
@ -2970,7 +3008,10 @@ static int glink_tx_common(void *handle, void *pkt_priv,
else else
xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info); xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info);
glink_tx_common_err:
rwref_read_put(&ctx->ch_state_lhb2); rwref_read_put(&ctx->ch_state_lhb2);
glink_tx_common_err_2:
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
@ -3011,13 +3052,15 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size)
struct glink_core_rx_intent *intent_ptr; struct glink_core_rx_intent *intent_ptr;
int ret = 0; int ret = 0;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
/* Can only queue rx intents if channel is fully opened */ /* Can only queue rx intents if channel is fully opened */
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
@ -3026,13 +3069,16 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size)
GLINK_ERR_CH(ctx, GLINK_ERR_CH(ctx,
"%s: Intent pointer allocation failed size[%zu]\n", "%s: Intent pointer allocation failed size[%zu]\n",
__func__, size); __func__, size);
glink_put_ch_ctx(ctx, false);
return -ENOMEM; return -ENOMEM;
} }
GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id, GLINK_DBG_CH(ctx, "%s: L[%u]:%zu\n", __func__, intent_ptr->id,
intent_ptr->intent_size); intent_ptr->intent_size);
if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) if (ctx->transport_ptr->capabilities & GCAP_INTENTLESS) {
glink_put_ch_ctx(ctx, false);
return ret; return ret;
}
/* notify remote side of rx intent */ /* notify remote side of rx intent */
ret = ctx->transport_ptr->ops->tx_cmd_local_rx_intent( ret = ctx->transport_ptr->ops->tx_cmd_local_rx_intent(
@ -3040,7 +3086,7 @@ int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size)
if (ret) if (ret)
/* unable to transmit, dequeue intent */ /* unable to transmit, dequeue intent */
ch_remove_local_rx_intent(ctx, intent_ptr->id); ch_remove_local_rx_intent(ctx, intent_ptr->id);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_queue_rx_intent); EXPORT_SYMBOL(glink_queue_rx_intent);
@ -3059,20 +3105,25 @@ bool glink_rx_intent_exists(void *handle, size_t size)
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
struct glink_core_rx_intent *intent; struct glink_core_rx_intent *intent;
unsigned long flags; unsigned long flags;
int ret;
if (!ctx || !ch_is_fully_opened(ctx)) if (!ctx || !ch_is_fully_opened(ctx))
return false; return false;
ret = glink_get_ch_ctx(ctx);
if (ret)
return false;
spin_lock_irqsave(&ctx->local_rx_intent_lst_lock_lhc1, flags); spin_lock_irqsave(&ctx->local_rx_intent_lst_lock_lhc1, flags);
list_for_each_entry(intent, &ctx->local_rx_intent_list, list) { list_for_each_entry(intent, &ctx->local_rx_intent_list, list) {
if (size <= intent->intent_size) { if (size <= intent->intent_size) {
spin_unlock_irqrestore( spin_unlock_irqrestore(
&ctx->local_rx_intent_lst_lock_lhc1, flags); &ctx->local_rx_intent_lst_lock_lhc1, flags);
glink_put_ch_ctx(ctx, false);
return true; return true;
} }
} }
spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags); spin_unlock_irqrestore(&ctx->local_rx_intent_lst_lock_lhc1, flags);
glink_put_ch_ctx(ctx, false);
return false; return false;
} }
EXPORT_SYMBOL(glink_rx_intent_exists); EXPORT_SYMBOL(glink_rx_intent_exists);
@ -3093,11 +3144,15 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse)
uint32_t id; uint32_t id;
int ret = 0; int ret = 0;
ret = glink_get_ch_ctx(ctx);
if (ret)
return ret;
liid_ptr = ch_get_local_rx_intent_notified(ctx, ptr); liid_ptr = ch_get_local_rx_intent_notified(ctx, ptr);
if (IS_ERR_OR_NULL(liid_ptr)) { if (IS_ERR_OR_NULL(liid_ptr)) {
/* invalid pointer */ /* invalid pointer */
GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr); GLINK_ERR_CH(ctx, "%s: Invalid pointer %p\n", __func__, ptr);
glink_put_ch_ctx(ctx, false);
return -EINVAL; return -EINVAL;
} }
@ -3123,7 +3178,7 @@ int glink_rx_done(void *handle, const void *ptr, bool reuse)
/* send rx done */ /* send rx done */
ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops, ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops,
ctx->lcid, id, reuse); ctx->lcid, id, reuse);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_rx_done); EXPORT_SYMBOL(glink_rx_done);
@ -3171,12 +3226,13 @@ int glink_sigs_set(void *handle, uint32_t sigs)
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret; int ret;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
@ -3186,6 +3242,7 @@ int glink_sigs_set(void *handle, uint32_t sigs)
ctx->lcid, ctx->lsigs); ctx->lcid, ctx->lsigs);
GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__); GLINK_INFO_CH(ctx, "%s: Sent SIGNAL SET command\n", __func__);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_sigs_set); EXPORT_SYMBOL(glink_sigs_set);
@ -3201,17 +3258,22 @@ EXPORT_SYMBOL(glink_sigs_set);
int glink_sigs_local_get(void *handle, uint32_t *sigs) int glink_sigs_local_get(void *handle, uint32_t *sigs)
{ {
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret;
if (!ctx || !sigs) if (!sigs)
return -EINVAL; return -EINVAL;
ret = glink_get_ch_ctx(ctx);
if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
*sigs = ctx->lsigs; *sigs = ctx->lsigs;
glink_put_ch_ctx(ctx, false);
return 0; return 0;
} }
EXPORT_SYMBOL(glink_sigs_local_get); EXPORT_SYMBOL(glink_sigs_local_get);
@ -3227,17 +3289,23 @@ EXPORT_SYMBOL(glink_sigs_local_get);
int glink_sigs_remote_get(void *handle, uint32_t *sigs) int glink_sigs_remote_get(void *handle, uint32_t *sigs)
{ {
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret;
if (!ctx || !sigs) if (!sigs)
return -EINVAL; return -EINVAL;
ret = glink_get_ch_ctx(ctx);
if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
*sigs = ctx->rsigs; *sigs = ctx->rsigs;
glink_put_ch_ctx(ctx, false);
return 0; return 0;
} }
EXPORT_SYMBOL(glink_sigs_remote_get); EXPORT_SYMBOL(glink_sigs_remote_get);
@ -3333,12 +3401,16 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size)
int ret; int ret;
unsigned long req_rate_kBps; unsigned long req_rate_kBps;
if (!ctx || !latency_us || !pkt_size) if (!latency_us || !pkt_size)
return -EINVAL; return -EINVAL;
ret = glink_get_ch_ctx(ctx);
if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
@ -3348,7 +3420,7 @@ int glink_qos_latency(void *handle, unsigned long latency_us, size_t pkt_size)
if (ret < 0) if (ret < 0)
GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n", GLINK_ERR_CH(ctx, "%s: QoS %lu:%zu cannot be met\n",
__func__, latency_us, pkt_size); __func__, latency_us, pkt_size);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_qos_latency); EXPORT_SYMBOL(glink_qos_latency);
@ -3366,16 +3438,18 @@ int glink_qos_cancel(void *handle)
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret; int ret;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
ret = glink_qos_reset_priority(ctx); ret = glink_qos_reset_priority(ctx);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_qos_cancel); EXPORT_SYMBOL(glink_qos_cancel);
@ -3396,12 +3470,13 @@ int glink_qos_start(void *handle)
int ret; int ret;
unsigned long flags; unsigned long flags;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
return ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return -EBUSY; return -EBUSY;
} }
@ -3410,6 +3485,7 @@ int glink_qos_start(void *handle)
ret = glink_qos_add_ch_tx_intent(ctx); ret = glink_qos_add_ch_tx_intent(ctx);
spin_unlock(&ctx->tx_lists_lock_lhc3); spin_unlock(&ctx->tx_lists_lock_lhc3);
spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags); spin_unlock_irqrestore(&ctx->transport_ptr->tx_ready_lock_lhb3, flags);
glink_put_ch_ctx(ctx, false);
return ret; return ret;
} }
EXPORT_SYMBOL(glink_qos_start); EXPORT_SYMBOL(glink_qos_start);
@ -3428,16 +3504,20 @@ EXPORT_SYMBOL(glink_qos_start);
unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size) unsigned long glink_qos_get_ramp_time(void *handle, size_t pkt_size)
{ {
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return (unsigned long)-EINVAL; if (ret)
return (unsigned long)ret;
if (!ch_is_fully_opened(ctx)) { if (!ch_is_fully_opened(ctx)) {
GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n", GLINK_ERR_CH(ctx, "%s: Channel is not fully opened\n",
__func__); __func__);
glink_put_ch_ctx(ctx, false);
return (unsigned long)-EBUSY; return (unsigned long)-EBUSY;
} }
glink_put_ch_ctx(ctx, false);
return ctx->transport_ptr->ops->get_power_vote_ramp_time( return ctx->transport_ptr->ops->get_power_vote_ramp_time(
ctx->transport_ptr->ops, ctx->transport_ptr->ops,
glink_prio_to_power_state(ctx->transport_ptr, glink_prio_to_power_state(ctx->transport_ptr,
@ -3521,12 +3601,16 @@ EXPORT_SYMBOL(glink_rpm_mask_rx_interrupt);
int glink_wait_link_down(void *handle) int glink_wait_link_down(void *handle)
{ {
struct channel_ctx *ctx = (struct channel_ctx *)handle; struct channel_ctx *ctx = (struct channel_ctx *)handle;
int ret;
if (!ctx) ret = glink_get_ch_ctx(ctx);
return -EINVAL; if (ret)
if (!ctx->transport_ptr) return ret;
if (!ctx->transport_ptr) {
glink_put_ch_ctx(ctx, false);
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
glink_put_ch_ctx(ctx, false);
return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops); return ctx->transport_ptr->ops->wait_link_down(ctx->transport_ptr->ops);
} }
EXPORT_SYMBOL(glink_wait_link_down); EXPORT_SYMBOL(glink_wait_link_down);
@ -6019,6 +6103,7 @@ EXPORT_SYMBOL(glink_get_xprt_log_ctx);
static int glink_init(void) static int glink_init(void)
{ {
log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0); log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "glink", 0);
rwlock_init(&magic_lock);
if (!log_ctx) if (!log_ctx)
GLINK_ERR("%s: unable to create log context\n", __func__); GLINK_ERR("%s: unable to create log context\n", __func__);
glink_debugfs_init(); glink_debugfs_init();