soc: qcom: msm_glink_pkt: Register and wait for link up notification

The user space clients sometimes open the device before the underlying
transport available which results in open error and cause multiple re-tries
from the clients. This leads to excessive logging of open error messages.

Register for link state notification and block the client open until link
available or user define timer expires.

CRs-Fixed: 1018542
Change-Id: I4e56982700f3444f96e1100c0ce272d36d3423a5
Signed-off-by: Dhoat Harpal <hdhoat@codeaurora.org>
This commit is contained in:
Arun Kumar Neelakantam 2016-05-16 19:32:08 +05:30 committed by Kyle Yan
parent 05360211f8
commit 84f558918f

View file

@ -100,6 +100,9 @@
* sigs_updated: flag to check signal update.
* open_time_wait: wait time for channel to fully open.
* in_reset: flag to check SSR state.
* link_info: structure to hold link information.
* link_state_handle: handle to get link state events.
* link_up: flag to check link is up or not.
*/
struct glink_pkt_dev {
struct list_head dev_list;
@ -129,6 +132,10 @@ struct glink_pkt_dev {
int sigs_updated;
int open_time_wait;
int in_reset;
struct glink_link_info link_info;
void *link_state_handle;
bool link_up;
};
/**
@ -215,7 +222,7 @@ do { \
#define GLINK_PKT_ERR(x...) \
do { \
pr_err("<GLINK_PKT> err: "x); \
pr_err_ratelimited("<GLINK_PKT> err: "x); \
GLINK_PKT_LOG_STRING(x); \
} while (0)
@ -303,6 +310,33 @@ static void packet_arrival_worker(struct work_struct *work)
mutex_unlock(&devp->ch_lock);
}
/**
* glink_pkt_link_state_cb() - Callback to receive link state updates
* @cb_info: Information containing link & its state.
* @priv: Private data passed during the link state registration.
*
* This function is called by the GLINK core to notify the Glink Pkt drivers
* regarding the link state updates. This function is registered with the
* GLINK core by Glink pkt drivers with glink_register_link_state_cb().
*/
static void glink_pkt_link_state_cb(struct glink_link_state_cb_info *cb_info,
void *priv)
{
struct glink_pkt_dev *devp = (struct glink_pkt_dev *)priv;
if (!cb_info)
return;
if (!devp)
return;
if (cb_info->link_state == GLINK_LINK_STATE_UP) {
devp->link_up = true;
wake_up_interruptible(&devp->ch_opened_wait_queue);
} else if (cb_info->link_state == GLINK_LINK_STATE_DOWN) {
devp->link_up = false;
}
}
/**
* glink_pkt_notify_rx() - Rx data Callback from G-Link core layer
* handle: Opaque Channel handle returned by GLink.
@ -885,7 +919,7 @@ int glink_pkt_open(struct inode *inode, struct file *file)
{
int ret = 0;
struct glink_pkt_dev *devp = NULL;
int wait_time;
int wait_time_msecs;
devp = container_of(inode->i_cdev, struct glink_pkt_dev, cdev);
if (!devp) {
@ -895,13 +929,13 @@ int glink_pkt_open(struct inode *inode, struct file *file)
GLINK_PKT_INFO("Begin %s() on dev id:%d open_time_wait[%d] by [%s]\n",
__func__, devp->i, devp->open_time_wait, current->comm);
file->private_data = devp;
wait_time = devp->open_time_wait;
wait_time_msecs = devp->open_time_wait * 1000;
mutex_lock(&devp->ch_lock);
/* waiting for previous close to complete */
if (devp->handle && devp->ref_cnt == 0) {
mutex_unlock(&devp->ch_lock);
if (wait_time < 0) {
if (wait_time_msecs < 0) {
ret = wait_event_interruptible(
devp->ch_opened_wait_queue,
devp->ch_state == GLINK_LOCAL_DISCONNECTED);
@ -909,10 +943,11 @@ int glink_pkt_open(struct inode *inode, struct file *file)
ret = wait_event_interruptible_timeout(
devp->ch_opened_wait_queue,
devp->ch_state == GLINK_LOCAL_DISCONNECTED,
msecs_to_jiffies(wait_time * 1000));
msecs_to_jiffies(wait_time_msecs));
if (ret >= 0)
wait_time_msecs = jiffies_to_msecs(ret);
if (ret == 0)
ret = -ETIMEDOUT;
wait_time = ret;
}
if (ret < 0) {
GLINK_PKT_ERR(
@ -924,6 +959,35 @@ int glink_pkt_open(struct inode *inode, struct file *file)
}
if (!devp->handle) {
mutex_unlock(&devp->ch_lock);
/*
* Wait for the link to be complete up so we know
* the remote is ready enough.
*/
if (wait_time_msecs < 0) {
ret = wait_event_interruptible(
devp->ch_opened_wait_queue,
devp->link_up == true);
} else {
ret = wait_event_interruptible_timeout(
devp->ch_opened_wait_queue,
devp->link_up == true,
msecs_to_jiffies(wait_time_msecs));
if (ret >= 0)
wait_time_msecs = jiffies_to_msecs(ret);
if (ret == 0)
ret = -ETIMEDOUT;
}
mutex_lock(&devp->ch_lock);
if (ret < 0) {
GLINK_PKT_ERR(
"%s: Link not up edge[%s] name[%s] rc:%d\n",
__func__, devp->open_cfg.edge,
devp->open_cfg.name, ret);
devp->handle = NULL;
goto error;
}
devp->handle = glink_open(&devp->open_cfg);
if (IS_ERR_OR_NULL(devp->handle)) {
GLINK_PKT_ERR(
@ -938,9 +1002,9 @@ int glink_pkt_open(struct inode *inode, struct file *file)
mutex_unlock(&devp->ch_lock);
/*
* Wait for the channel to be complete open state so we know
* the remote is ready enough.
* the remote client is ready enough.
*/
if (wait_time < 0) {
if (wait_time_msecs < 0) {
ret = wait_event_interruptible(
devp->ch_opened_wait_queue,
devp->ch_state == GLINK_CONNECTED);
@ -948,7 +1012,7 @@ int glink_pkt_open(struct inode *inode, struct file *file)
ret = wait_event_interruptible_timeout(
devp->ch_opened_wait_queue,
devp->ch_state == GLINK_CONNECTED,
msecs_to_jiffies(wait_time * 1000));
msecs_to_jiffies(wait_time_msecs));
if (ret == 0)
ret = -ETIMEDOUT;
}
@ -1059,6 +1123,10 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i)
devp->open_cfg.options |= GLINK_OPT_INITIAL_XPORT;
devp->open_cfg.priv = devp;
devp->link_up = false;
devp->link_info.edge = devp->open_cfg.edge;
devp->link_info.glink_link_state_notif_cb =
glink_pkt_link_state_cb;
devp->i = i;
devp->poll_mode = 0;
devp->ws_locked = 0;
@ -1075,6 +1143,15 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i)
wakeup_source_init(&devp->pa_ws, devp->dev_name);
INIT_WORK(&devp->packet_arrival_work, packet_arrival_worker);
devp->link_state_handle =
glink_register_link_state_cb(&devp->link_info, devp);
if (IS_ERR_OR_NULL(devp->link_state_handle)) {
GLINK_PKT_ERR(
"%s: link state cb reg. failed edge[%s] name[%s]\n",
__func__, devp->open_cfg.edge, devp->open_cfg.name);
ret = PTR_ERR(devp->link_state_handle);
return ret;
}
cdev_init(&devp->cdev, &glink_pkt_fops);
devp->cdev.owner = THIS_MODULE;
@ -1126,6 +1203,9 @@ static void glink_pkt_core_deinit(void)
mutex_lock(&glink_pkt_dev_lock_lha1);
list_for_each_entry_safe(glink_pkt_devp, index, &glink_pkt_dev_list,
dev_list) {
if (glink_pkt_devp->link_state_handle)
glink_unregister_link_state_cb(
glink_pkt_devp->link_state_handle);
cdev_del(&glink_pkt_devp->cdev);
list_del(&glink_pkt_devp->dev_list);
device_destroy(glink_pkt_classp,