From 71f3e30f8e0519c6eeb4113ce220dce9598c6872 Mon Sep 17 00:00:00 2001 From: Vivek Golani Date: Thu, 21 Jan 2021 11:43:49 +0530 Subject: [PATCH] diag: Enable graceful transfer of transport Avoid channel close by setting flags if socket transport close is invoked after rpmsg transport has been probed. Change-Id: I5d94894e05bbbe079a566d9356eb08a6aeac7799 Signed-off-by: Vivek Golani --- drivers/char/diag/diagfwd_peripheral.c | 15 +++++++++++++++ drivers/char/diag/diagfwd_rpmsg.c | 9 ++++++--- drivers/char/diag/diagfwd_rpmsg.h | 2 ++ drivers/char/diag/diagfwd_socket.c | 23 ++++++++++++++++++++++- drivers/char/diag/diagfwd_socket.h | 4 +++- 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 0ded8ba0fbe9..4bc7a57affb3 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1345,11 +1345,26 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) int diagfwd_channel_close(struct diagfwd_info *fwd_info) { + struct diag_rpmsg_info *rpmsg_info = NULL; + struct diag_socket_info *socket_info = NULL; + if (!fwd_info) return -EIO; mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; + rpmsg_info = diag_get_rpmsg_info_ptr(fwd_info->type, + fwd_info->peripheral); + socket_info = diag_get_socket_info_ptr(fwd_info->type, + fwd_info->peripheral); + + if (rpmsg_info && socket_info && rpmsg_info->probed + && socket_info->reset_flag) { + mutex_unlock( + &driver->diagfwd_channel_mutex[fwd_info->peripheral]); + return 0; + } + if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) fwd_info->c_ops->close(fwd_info); diff --git a/drivers/char/diag/diagfwd_rpmsg.c b/drivers/char/diag/diagfwd_rpmsg.c index 949340166aa1..c194e831551d 100644 --- a/drivers/char/diag/diagfwd_rpmsg.c +++ b/drivers/char/diag/diagfwd_rpmsg.c @@ -678,7 +678,7 @@ static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work) if (!rpmsg_info->buf1 && !rpmsg_info->buf2) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "dropping data for %s len %d\n", + "retry data send for %s len %d\n", rpmsg_info->name, rx_item->rx_buf_size); err_flag = 1; goto err_handling; @@ -738,7 +738,7 @@ end: return; } -static struct diag_rpmsg_info *get_info_ptr(int type, int peripheral) +struct diag_rpmsg_info *diag_get_rpmsg_info_ptr(int type, int peripheral) { if (type == TYPE_CMD) return &rpmsg_cmd[peripheral]; @@ -771,7 +771,7 @@ void rpmsg_mark_buffers_free(uint8_t peripheral, uint8_t type, int buf_num) return; } - rpmsg_info = get_info_ptr(type, peripheral); + rpmsg_info = diag_get_rpmsg_info_ptr(type, peripheral); if (!rpmsg_info) return; @@ -849,6 +849,7 @@ static void __diag_rpmsg_init(struct diag_rpmsg_info *rpmsg_info) mutex_lock(&driver->rpmsginfo_mutex[PERI_RPMSG]); rpmsg_info->hdl = NULL; rpmsg_info->fwd_ctxt = NULL; + rpmsg_info->probed = 0; atomic_set(&rpmsg_info->opened, 0); atomic_set(&rpmsg_info->diag_state, 0); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -1046,6 +1047,7 @@ static int diag_rpmsg_probe(struct rpmsg_device *rpdev) rpmsg_info->hdl = rpdev; atomic_set(&rpmsg_info->opened, 1); mutex_unlock(&driver->rpmsginfo_mutex[PERI_RPMSG]); + rpmsg_info->probed = 1; dev_set_drvdata(&rpdev->dev, rpmsg_info); diagfwd_channel_read(rpmsg_info->fwd_ctxt); queue_work(rpmsg_info->wq, &rpmsg_info->open_work); @@ -1075,6 +1077,7 @@ static void diag_rpmsg_remove(struct rpmsg_device *rpdev) mutex_lock(&driver->rpmsginfo_mutex[PERI_RPMSG]); atomic_set(&rpmsg_info->opened, 0); mutex_unlock(&driver->rpmsginfo_mutex[PERI_RPMSG]); + rpmsg_info->probed = 0; queue_work(rpmsg_info->wq, &rpmsg_info->close_work); } } diff --git a/drivers/char/diag/diagfwd_rpmsg.h b/drivers/char/diag/diagfwd_rpmsg.h index 437e590164a4..6a973bac5c07 100644 --- a/drivers/char/diag/diagfwd_rpmsg.h +++ b/drivers/char/diag/diagfwd_rpmsg.h @@ -12,6 +12,7 @@ struct diag_rpmsg_info { uint8_t peripheral; uint8_t type; uint8_t inited; + uint8_t probed; atomic_t opened; atomic_t diag_state; uint32_t fifo_size; @@ -44,5 +45,6 @@ void diag_rpmsg_early_exit(void); void diag_rpmsg_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt); int diag_rpmsg_check_state(void *ctxt); void rpmsg_mark_buffers_free(uint8_t peripheral, uint8_t type, int buf_num); +struct diag_rpmsg_info *diag_get_rpmsg_info_ptr(int type, int peripheral); #endif diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index ebfa7a69b81b..be3b34bbad16 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #include @@ -244,6 +244,22 @@ struct diag_socket_info socket_dci_cmd[NUM_PERIPHERALS] = { } }; +struct diag_socket_info *diag_get_socket_info_ptr(int type, int peripheral) +{ + if (type == TYPE_CMD) + return &socket_cmd[peripheral]; + else if (type == TYPE_CNTL) + return &socket_cntl[peripheral]; + else if (type == TYPE_DATA) + return &socket_data[peripheral]; + else if (type == TYPE_DCI_CMD) + return &socket_dci_cmd[peripheral]; + else if (type == TYPE_DCI) + return &socket_dci[peripheral]; + else + return NULL; +} + struct restart_notifier_block { unsigned int processor; char *name; @@ -611,7 +627,9 @@ static void socket_read_work_fn(struct work_struct *work) err = sock_error(info->hdl->sk); mutex_unlock(&info->socket_info_mutex); if (unlikely(err == -ENETRESET)) { + info->reset_flag = 1; socket_close_channel(info); + info->reset_flag = 0; if (info->port_type == PORT_TYPE_SERVER) socket_init_work_fn(&info->init_work); diag_ws_release(); @@ -831,7 +849,9 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) mutex_lock(channel_mutex); diagfwd_channel_read_done(info->fwd_ctxt, buf, 0); mutex_unlock(channel_mutex); + info->reset_flag = 1; socket_close_channel(info); + info->reset_flag = 0; if (info->port_type == PORT_TYPE_SERVER) socket_init_work_fn(&info->init_work); return read_len; @@ -980,6 +1000,7 @@ static void __diag_socket_init(struct diag_socket_info *info) info->hdl = NULL; info->fwd_ctxt = NULL; info->data_ready = 0; + info->reset_flag = 0; atomic_set(&info->flow_cnt, 0); spin_lock_init(&info->lock); strlcpy(wq_name, info->name, sizeof(wq_name)); diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h index eec1bfcdc41f..d113ed543cf0 100644 --- a/drivers/char/diag/diagfwd_socket.h +++ b/drivers/char/diag/diagfwd_socket.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef DIAGFWD_SOCKET_H @@ -33,6 +33,7 @@ struct diag_socket_info { uint8_t type; uint8_t port_type; uint8_t inited; + uint8_t reset_flag; atomic_t opened; atomic_t diag_state; uint32_t pkt_len; @@ -68,4 +69,5 @@ int diag_socket_check_state(void *ctxt); int diag_socket_init(void); void diag_socket_exit(void); int diag_socket_init_peripheral(uint8_t peripheral); +struct diag_socket_info *diag_get_socket_info_ptr(int type, int peripheral); #endif