From 01a69402cf9d38ff180345d55c2ee51c7e89fbc7 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 20:50:03 +0200 Subject: Adding upstream version 6.8.9. Signed-off-by: Daniel Baumann --- drivers/hid/intel-ish-hid/ishtp/bus.c | 4 +- drivers/hid/intel-ish-hid/ishtp/client.c | 189 +++++++++++++++++++++++++++++-- 2 files changed, 180 insertions(+), 13 deletions(-) (limited to 'drivers/hid/intel-ish-hid/ishtp') diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 7fc738a223..03d5601ce8 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -378,7 +378,7 @@ static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = { .restore = ishtp_cl_device_resume, }; -static struct bus_type ishtp_cl_bus_type = { +static const struct bus_type ishtp_cl_bus_type = { .name = "ishtp", .dev_groups = ishtp_cl_dev_groups, .probe = ishtp_cl_device_probe, @@ -722,6 +722,8 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); list_for_each_entry(cl, &ishtp_dev->cl_list, link) { cl->state = ISHTP_CL_DISCONNECTED; + if (warm_reset && cl->device->reference_count) + continue; /* * Wake any pending process. The waiter would check dev->state diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c index 2d92fc129c..8a7f2f6a4f 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.c +++ b/drivers/hid/intel-ish-hid/ishtp/client.c @@ -49,7 +49,9 @@ static void ishtp_read_list_flush(struct ishtp_cl *cl) list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list) if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) { list_del(&rb->list); - ishtp_io_rb_free(rb); + spin_lock(&cl->free_list_spinlock); + list_add_tail(&rb->list, &cl->free_rb_list.list); + spin_unlock(&cl->free_list_spinlock); } spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags); } @@ -339,16 +341,17 @@ static bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl) } /** - * ishtp_cl_connect() - Send connect request to firmware + * ishtp_cl_connect_to_fw() - Send connect request to firmware * @cl: client device instance * - * Send a connect request for a client to firmware. If successful it will - * RX and TX ring buffers + * Send a connect request to the firmware and wait for firmware response. + * If there is successful connection response from the firmware, change + * client state to ISHTP_CL_CONNECTED, and bind client to related + * firmware client_id. * - * Return: 0 if successful connect response from the firmware and able - * to bind and allocate ring buffers or error code on failure + * Return: 0 for success and error code on failure */ -int ishtp_cl_connect(struct ishtp_cl *cl) +static int ishtp_cl_connect_to_fw(struct ishtp_cl *cl) { struct ishtp_device *dev; int rets; @@ -358,8 +361,6 @@ int ishtp_cl_connect(struct ishtp_cl *cl) dev = cl->dev; - dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); - if (ishtp_cl_is_other_connecting(cl)) { dev->print_log(dev, "%s() Busy\n", __func__); return -EBUSY; @@ -405,6 +406,38 @@ int ishtp_cl_connect(struct ishtp_cl *cl) return rets; } + return rets; +} + +/** + * ishtp_cl_connect() - Build connection with firmware + * @cl: client device instance + * + * Call ishtp_cl_connect_to_fw() to connect and bind to firmware. If successful, + * allocate RX and TX ring buffers, and start flow control with firmware to + * start communication. + * + * Return: 0 if there is successful connection to the firmware, allocate + * ring buffers. + */ +int ishtp_cl_connect(struct ishtp_cl *cl) +{ + struct ishtp_device *dev; + int rets; + + if (!cl || !cl->dev) + return -ENODEV; + + dev = cl->dev; + + dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); + + rets = ishtp_cl_connect_to_fw(cl); + if (rets) { + dev->print_log(dev, "%s() Connect to fw failed\n", __func__); + return rets; + } + rets = ishtp_cl_alloc_rx_ring(cl); if (rets) { dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__); @@ -422,15 +455,147 @@ int ishtp_cl_connect(struct ishtp_cl *cl) return rets; } - /* Upon successful connection and allocation, emit flow-control */ + /* + * Upon successful connection and allocation, start flow-control. + */ rets = ishtp_cl_read_start(cl); - dev->print_log(dev, "%s() successful\n", __func__); - return rets; } EXPORT_SYMBOL(ishtp_cl_connect); +/** + * ishtp_cl_establish_connection() - Establish connection with the firmware + * @cl: client device instance + * @uuid: uuid of the client to search + * @tx_size: TX ring buffer size + * @rx_size: RX ring buffer size + * @reset: true if called for reset connection, otherwise for first connection + * + * This is a helper function for client driver to build connection with firmware. + * If it's first time connecting to the firmware, set reset to false, this + * function will link client to bus, find client id and send connect request to + * the firmware. + * + * If it's called for reset handler where client lost connection after + * firmware reset, set reset to true, this function will reinit client state and + * establish connection again. In this case, this function reuses current client + * structure and ring buffers to avoid allocation failure and memory fragments. + * + * Return: 0 for successful connection with the firmware, + * or error code on failure + */ +int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid, + int tx_size, int rx_size, bool reset) +{ + struct ishtp_device *dev; + struct ishtp_fw_client *fw_client; + int rets; + + if (!cl || !cl->dev) + return -ENODEV; + + dev = cl->dev; + + ishtp_set_connection_state(cl, ISHTP_CL_INITIALIZING); + + /* reinit ishtp_cl structure if call for reset */ + if (reset) { + cl->host_client_id = 0; + cl->fw_client_id = 0; + cl->ishtp_flow_ctrl_creds = 0; + cl->out_flow_ctrl_creds = 0; + + cl->last_tx_path = CL_TX_PATH_IPC; + cl->last_dma_acked = 1; + cl->last_dma_addr = NULL; + cl->last_ipc_acked = 1; + + cl->sending = 0; + cl->err_send_msg = 0; + cl->err_send_fc = 0; + + cl->send_msg_cnt_ipc = 0; + cl->send_msg_cnt_dma = 0; + cl->recv_msg_cnt_ipc = 0; + cl->recv_msg_cnt_dma = 0; + cl->recv_msg_num_frags = 0; + cl->ishtp_flow_ctrl_cnt = 0; + cl->out_flow_ctrl_cnt = 0; + } + + /* link to bus */ + rets = ishtp_cl_link(cl); + if (rets) { + dev->print_log(dev, "%s() ishtp_cl_link failed\n", __func__); + return rets; + } + + /* find firmware client */ + fw_client = ishtp_fw_cl_get_client(dev, uuid); + if (!fw_client) { + dev->print_log(dev, + "%s() ish client uuid not found\n", __func__); + return -ENOENT; + } + + ishtp_set_tx_ring_size(cl, tx_size); + ishtp_set_rx_ring_size(cl, rx_size); + + ishtp_cl_set_fw_client_id(cl, ishtp_get_fw_client_id(fw_client)); + + ishtp_set_connection_state(cl, ISHTP_CL_CONNECTING); + + /* + * For reset case, not allocate tx/rx ring buffer which are already + * done in ishtp_cl_connect() during first connection. + */ + if (reset) { + rets = ishtp_cl_connect_to_fw(cl); + if (!rets) + rets = ishtp_cl_read_start(cl); + else + dev->print_log(dev, + "%s() connect to fw failed\n", __func__); + } else { + rets = ishtp_cl_connect(cl); + } + + return rets; +} +EXPORT_SYMBOL(ishtp_cl_establish_connection); + +/** + * ishtp_cl_destroy_connection() - Disconnect with the firmware + * @cl: client device instance + * @reset: true if called for firmware reset, false for normal disconnection + * + * This is a helper function for client driver to disconnect with firmware, + * unlink to bus and flush message queue. + */ +void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset) +{ + if (!cl) + return; + + if (reset) { + /* + * For reset case, connection is already lost during fw reset. + * Just set state to DISCONNECTED is enough. + */ + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTED); + } else { + if (cl->state != ISHTP_CL_DISCONNECTED) { + ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTING); + ishtp_cl_disconnect(cl); + } + } + + ishtp_cl_unlink(cl); + ishtp_cl_flush_queues(cl); +} +EXPORT_SYMBOL(ishtp_cl_destroy_connection); + /** * ishtp_cl_read_start() - Prepare to read client message * @cl: client device instance -- cgit v1.2.3