162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ISHTP client logic 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2003-2016, Intel Corporation. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/sched.h> 1062306a36Sopenharmony_ci#include <linux/wait.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1362306a36Sopenharmony_ci#include <asm/cacheflush.h> 1462306a36Sopenharmony_ci#include "hbm.h" 1562306a36Sopenharmony_ci#include "client.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciint ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci unsigned long tx_free_flags; 2062306a36Sopenharmony_ci int size; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 2362306a36Sopenharmony_ci size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length; 2462306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return size; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciint ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return cl->tx_ring_free_size; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_get_tx_free_rings); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/** 3762306a36Sopenharmony_ci * ishtp_read_list_flush() - Flush read queue 3862306a36Sopenharmony_ci * @cl: ishtp client instance 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Used to remove all entries from read queue for a client 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic void ishtp_read_list_flush(struct ishtp_cl *cl) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct ishtp_cl_rb *rb; 4562306a36Sopenharmony_ci struct ishtp_cl_rb *next; 4662306a36Sopenharmony_ci unsigned long flags; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci spin_lock_irqsave(&cl->dev->read_list_spinlock, flags); 4962306a36Sopenharmony_ci list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list) 5062306a36Sopenharmony_ci if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) { 5162306a36Sopenharmony_ci list_del(&rb->list); 5262306a36Sopenharmony_ci ishtp_io_rb_free(rb); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * ishtp_cl_flush_queues() - Flush all queues for a client 5962306a36Sopenharmony_ci * @cl: ishtp client instance 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Used to remove all queues for a client. This is called when a client device 6262306a36Sopenharmony_ci * needs reset due to error, S3 resume or during module removal 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * Return: 0 on success else -EINVAL if device is NULL 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ciint ishtp_cl_flush_queues(struct ishtp_cl *cl) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 6962306a36Sopenharmony_ci return -EINVAL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ishtp_read_list_flush(cl); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_flush_queues); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * ishtp_cl_init() - Initialize all fields of a client device 7962306a36Sopenharmony_ci * @cl: ishtp client instance 8062306a36Sopenharmony_ci * @dev: ishtp device 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Initializes a client device fields: Init spinlocks, init queues etc. 8362306a36Sopenharmony_ci * This function is called during new client creation 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_cistatic void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci memset(cl, 0, sizeof(struct ishtp_cl)); 8862306a36Sopenharmony_ci init_waitqueue_head(&cl->wait_ctrl_res); 8962306a36Sopenharmony_ci spin_lock_init(&cl->free_list_spinlock); 9062306a36Sopenharmony_ci spin_lock_init(&cl->in_process_spinlock); 9162306a36Sopenharmony_ci spin_lock_init(&cl->tx_list_spinlock); 9262306a36Sopenharmony_ci spin_lock_init(&cl->tx_free_list_spinlock); 9362306a36Sopenharmony_ci spin_lock_init(&cl->fc_spinlock); 9462306a36Sopenharmony_ci INIT_LIST_HEAD(&cl->link); 9562306a36Sopenharmony_ci cl->dev = dev; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci INIT_LIST_HEAD(&cl->free_rb_list.list); 9862306a36Sopenharmony_ci INIT_LIST_HEAD(&cl->tx_list.list); 9962306a36Sopenharmony_ci INIT_LIST_HEAD(&cl->tx_free_list.list); 10062306a36Sopenharmony_ci INIT_LIST_HEAD(&cl->in_process_list.list); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci cl->rx_ring_size = CL_DEF_RX_RING_SIZE; 10362306a36Sopenharmony_ci cl->tx_ring_size = CL_DEF_TX_RING_SIZE; 10462306a36Sopenharmony_ci cl->tx_ring_free_size = cl->tx_ring_size; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* dma */ 10762306a36Sopenharmony_ci cl->last_tx_path = CL_TX_PATH_IPC; 10862306a36Sopenharmony_ci cl->last_dma_acked = 1; 10962306a36Sopenharmony_ci cl->last_dma_addr = NULL; 11062306a36Sopenharmony_ci cl->last_ipc_acked = 1; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * ishtp_cl_allocate() - allocates client structure and sets it up. 11562306a36Sopenharmony_ci * @cl_device: ishtp client device 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * Allocate memory for new client device and call to initialize each field. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * Return: The allocated client instance or NULL on failure 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistruct ishtp_cl *ishtp_cl_allocate(struct ishtp_cl_device *cl_device) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct ishtp_cl *cl; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci cl = kmalloc(sizeof(struct ishtp_cl), GFP_KERNEL); 12662306a36Sopenharmony_ci if (!cl) 12762306a36Sopenharmony_ci return NULL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ishtp_cl_init(cl, cl_device->ishtp_dev); 13062306a36Sopenharmony_ci return cl; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_allocate); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * ishtp_cl_free() - Frees a client device 13662306a36Sopenharmony_ci * @cl: client device instance 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Frees a client device 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_civoid ishtp_cl_free(struct ishtp_cl *cl) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct ishtp_device *dev; 14362306a36Sopenharmony_ci unsigned long flags; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!cl) 14662306a36Sopenharmony_ci return; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci dev = cl->dev; 14962306a36Sopenharmony_ci if (!dev) 15062306a36Sopenharmony_ci return; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci spin_lock_irqsave(&dev->cl_list_lock, flags); 15362306a36Sopenharmony_ci ishtp_cl_free_rx_ring(cl); 15462306a36Sopenharmony_ci ishtp_cl_free_tx_ring(cl); 15562306a36Sopenharmony_ci kfree(cl); 15662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->cl_list_lock, flags); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_free); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * ishtp_cl_link() - Reserve a host id and link the client instance 16262306a36Sopenharmony_ci * @cl: client device instance 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * This allocates a single bit in the hostmap. This function will make sure 16562306a36Sopenharmony_ci * that not many client sessions are opened at the same time. Once allocated 16662306a36Sopenharmony_ci * the client device instance is added to the ishtp device in the current 16762306a36Sopenharmony_ci * client list 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Return: 0 or error code on failure 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ciint ishtp_cl_link(struct ishtp_cl *cl) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct ishtp_device *dev; 17462306a36Sopenharmony_ci unsigned long flags, flags_cl; 17562306a36Sopenharmony_ci int id, ret = 0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci dev = cl->dev; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci spin_lock_irqsave(&dev->device_lock, flags); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (dev->open_handle_count >= ISHTP_MAX_OPEN_HANDLE_COUNT) { 18562306a36Sopenharmony_ci ret = -EMFILE; 18662306a36Sopenharmony_ci goto unlock_dev; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci id = find_first_zero_bit(dev->host_clients_map, ISHTP_CLIENTS_MAX); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (id >= ISHTP_CLIENTS_MAX) { 19262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->device_lock, flags); 19362306a36Sopenharmony_ci dev_err(&cl->device->dev, "id exceeded %d", ISHTP_CLIENTS_MAX); 19462306a36Sopenharmony_ci return -ENOENT; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci dev->open_handle_count++; 19862306a36Sopenharmony_ci cl->host_client_id = id; 19962306a36Sopenharmony_ci spin_lock_irqsave(&dev->cl_list_lock, flags_cl); 20062306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) { 20162306a36Sopenharmony_ci ret = -ENODEV; 20262306a36Sopenharmony_ci goto unlock_cl; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci list_add_tail(&cl->link, &dev->cl_list); 20562306a36Sopenharmony_ci set_bit(id, dev->host_clients_map); 20662306a36Sopenharmony_ci cl->state = ISHTP_CL_INITIALIZING; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciunlock_cl: 20962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->cl_list_lock, flags_cl); 21062306a36Sopenharmony_ciunlock_dev: 21162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->device_lock, flags); 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_link); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/** 21762306a36Sopenharmony_ci * ishtp_cl_unlink() - remove fw_cl from the client device list 21862306a36Sopenharmony_ci * @cl: client device instance 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * Remove a previously linked device to a ishtp device 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_civoid ishtp_cl_unlink(struct ishtp_cl *cl) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct ishtp_device *dev; 22562306a36Sopenharmony_ci struct ishtp_cl *pos; 22662306a36Sopenharmony_ci unsigned long flags; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* don't shout on error exit path */ 22962306a36Sopenharmony_ci if (!cl || !cl->dev) 23062306a36Sopenharmony_ci return; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci dev = cl->dev; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci spin_lock_irqsave(&dev->device_lock, flags); 23562306a36Sopenharmony_ci if (dev->open_handle_count > 0) { 23662306a36Sopenharmony_ci clear_bit(cl->host_client_id, dev->host_clients_map); 23762306a36Sopenharmony_ci dev->open_handle_count--; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->device_lock, flags); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * This checks that 'cl' is actually linked into device's structure, 24362306a36Sopenharmony_ci * before attempting 'list_del' 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci spin_lock_irqsave(&dev->cl_list_lock, flags); 24662306a36Sopenharmony_ci list_for_each_entry(pos, &dev->cl_list, link) 24762306a36Sopenharmony_ci if (cl->host_client_id == pos->host_client_id) { 24862306a36Sopenharmony_ci list_del_init(&pos->link); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->cl_list_lock, flags); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_unlink); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/** 25662306a36Sopenharmony_ci * ishtp_cl_disconnect() - Send disconnect request to firmware 25762306a36Sopenharmony_ci * @cl: client device instance 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Send a disconnect request for a client to firmware. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Return: 0 if successful disconnect response from the firmware or error 26262306a36Sopenharmony_ci * code on failure 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ciint ishtp_cl_disconnect(struct ishtp_cl *cl) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct ishtp_device *dev; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 26962306a36Sopenharmony_ci return -ENODEV; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci dev = cl->dev; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci dev->print_log(dev, "%s() state %d\n", __func__, cl->state); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (cl->state != ISHTP_CL_DISCONNECTING) { 27662306a36Sopenharmony_ci dev->print_log(dev, "%s() Disconnect in progress\n", __func__); 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (ishtp_hbm_cl_disconnect_req(dev, cl)) { 28162306a36Sopenharmony_ci dev->print_log(dev, "%s() Failed to disconnect\n", __func__); 28262306a36Sopenharmony_ci dev_err(&cl->device->dev, "failed to disconnect.\n"); 28362306a36Sopenharmony_ci return -ENODEV; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci wait_event_interruptible_timeout(cl->wait_ctrl_res, 28762306a36Sopenharmony_ci (dev->dev_state != ISHTP_DEV_ENABLED || 28862306a36Sopenharmony_ci cl->state == ISHTP_CL_DISCONNECTED), 28962306a36Sopenharmony_ci ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* 29262306a36Sopenharmony_ci * If FW reset arrived, this will happen. Don't check cl->, 29362306a36Sopenharmony_ci * as 'cl' may be freed already 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) { 29662306a36Sopenharmony_ci dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n", 29762306a36Sopenharmony_ci __func__); 29862306a36Sopenharmony_ci return -ENODEV; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (cl->state == ISHTP_CL_DISCONNECTED) { 30262306a36Sopenharmony_ci dev->print_log(dev, "%s() successful\n", __func__); 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return -ENODEV; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_disconnect); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/** 31162306a36Sopenharmony_ci * ishtp_cl_is_other_connecting() - Check other client is connecting 31262306a36Sopenharmony_ci * @cl: client device instance 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * Checks if other client with the same fw client id is connecting 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * Return: true if other client is connected else false 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct ishtp_device *dev; 32162306a36Sopenharmony_ci struct ishtp_cl *pos; 32262306a36Sopenharmony_ci unsigned long flags; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 32562306a36Sopenharmony_ci return false; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci dev = cl->dev; 32862306a36Sopenharmony_ci spin_lock_irqsave(&dev->cl_list_lock, flags); 32962306a36Sopenharmony_ci list_for_each_entry(pos, &dev->cl_list, link) { 33062306a36Sopenharmony_ci if ((pos->state == ISHTP_CL_CONNECTING) && (pos != cl) && 33162306a36Sopenharmony_ci cl->fw_client_id == pos->fw_client_id) { 33262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->cl_list_lock, flags); 33362306a36Sopenharmony_ci return true; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->cl_list_lock, flags); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return false; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/** 34262306a36Sopenharmony_ci * ishtp_cl_connect() - Send connect request to firmware 34362306a36Sopenharmony_ci * @cl: client device instance 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * Send a connect request for a client to firmware. If successful it will 34662306a36Sopenharmony_ci * RX and TX ring buffers 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Return: 0 if successful connect response from the firmware and able 34962306a36Sopenharmony_ci * to bind and allocate ring buffers or error code on failure 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ciint ishtp_cl_connect(struct ishtp_cl *cl) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct ishtp_device *dev; 35462306a36Sopenharmony_ci int rets; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 35762306a36Sopenharmony_ci return -ENODEV; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci dev = cl->dev; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (ishtp_cl_is_other_connecting(cl)) { 36462306a36Sopenharmony_ci dev->print_log(dev, "%s() Busy\n", __func__); 36562306a36Sopenharmony_ci return -EBUSY; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (ishtp_hbm_cl_connect_req(dev, cl)) { 36962306a36Sopenharmony_ci dev->print_log(dev, "%s() HBM connect req fail\n", __func__); 37062306a36Sopenharmony_ci return -ENODEV; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rets = wait_event_interruptible_timeout(cl->wait_ctrl_res, 37462306a36Sopenharmony_ci (dev->dev_state == ISHTP_DEV_ENABLED && 37562306a36Sopenharmony_ci (cl->state == ISHTP_CL_CONNECTED || 37662306a36Sopenharmony_ci cl->state == ISHTP_CL_DISCONNECTED)), 37762306a36Sopenharmony_ci ishtp_secs_to_jiffies( 37862306a36Sopenharmony_ci ISHTP_CL_CONNECT_TIMEOUT)); 37962306a36Sopenharmony_ci /* 38062306a36Sopenharmony_ci * If FW reset arrived, this will happen. Don't check cl->, 38162306a36Sopenharmony_ci * as 'cl' may be freed already 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) { 38462306a36Sopenharmony_ci dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n", 38562306a36Sopenharmony_ci __func__); 38662306a36Sopenharmony_ci return -EFAULT; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (cl->state != ISHTP_CL_CONNECTED) { 39062306a36Sopenharmony_ci dev->print_log(dev, "%s() state != ISHTP_CL_CONNECTED\n", 39162306a36Sopenharmony_ci __func__); 39262306a36Sopenharmony_ci return -EFAULT; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rets = cl->status; 39662306a36Sopenharmony_ci if (rets) { 39762306a36Sopenharmony_ci dev->print_log(dev, "%s() Invalid status\n", __func__); 39862306a36Sopenharmony_ci return rets; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci rets = ishtp_cl_device_bind(cl); 40262306a36Sopenharmony_ci if (rets) { 40362306a36Sopenharmony_ci dev->print_log(dev, "%s() Bind error\n", __func__); 40462306a36Sopenharmony_ci ishtp_cl_disconnect(cl); 40562306a36Sopenharmony_ci return rets; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci rets = ishtp_cl_alloc_rx_ring(cl); 40962306a36Sopenharmony_ci if (rets) { 41062306a36Sopenharmony_ci dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__); 41162306a36Sopenharmony_ci /* if failed allocation, disconnect */ 41262306a36Sopenharmony_ci ishtp_cl_disconnect(cl); 41362306a36Sopenharmony_ci return rets; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci rets = ishtp_cl_alloc_tx_ring(cl); 41762306a36Sopenharmony_ci if (rets) { 41862306a36Sopenharmony_ci dev->print_log(dev, "%s() Alloc TX ring failed\n", __func__); 41962306a36Sopenharmony_ci /* if failed allocation, disconnect */ 42062306a36Sopenharmony_ci ishtp_cl_free_rx_ring(cl); 42162306a36Sopenharmony_ci ishtp_cl_disconnect(cl); 42262306a36Sopenharmony_ci return rets; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Upon successful connection and allocation, emit flow-control */ 42662306a36Sopenharmony_ci rets = ishtp_cl_read_start(cl); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci dev->print_log(dev, "%s() successful\n", __func__); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return rets; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_connect); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/** 43562306a36Sopenharmony_ci * ishtp_cl_read_start() - Prepare to read client message 43662306a36Sopenharmony_ci * @cl: client device instance 43762306a36Sopenharmony_ci * 43862306a36Sopenharmony_ci * Get a free buffer from pool of free read buffers and add to read buffer 43962306a36Sopenharmony_ci * pool to add contents. Send a flow control request to firmware to be able 44062306a36Sopenharmony_ci * send next message. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * Return: 0 if successful or error code on failure 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ciint ishtp_cl_read_start(struct ishtp_cl *cl) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct ishtp_device *dev; 44762306a36Sopenharmony_ci struct ishtp_cl_rb *rb; 44862306a36Sopenharmony_ci int rets; 44962306a36Sopenharmony_ci int i; 45062306a36Sopenharmony_ci unsigned long flags; 45162306a36Sopenharmony_ci unsigned long dev_flags; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 45462306a36Sopenharmony_ci return -ENODEV; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci dev = cl->dev; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (cl->state != ISHTP_CL_CONNECTED) 45962306a36Sopenharmony_ci return -ENODEV; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) 46262306a36Sopenharmony_ci return -ENODEV; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci i = ishtp_fw_cl_by_id(dev, cl->fw_client_id); 46562306a36Sopenharmony_ci if (i < 0) { 46662306a36Sopenharmony_ci dev_err(&cl->device->dev, "no such fw client %d\n", 46762306a36Sopenharmony_ci cl->fw_client_id); 46862306a36Sopenharmony_ci return -ENODEV; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* The current rb is the head of the free rb list */ 47262306a36Sopenharmony_ci spin_lock_irqsave(&cl->free_list_spinlock, flags); 47362306a36Sopenharmony_ci if (list_empty(&cl->free_rb_list.list)) { 47462306a36Sopenharmony_ci dev_warn(&cl->device->dev, 47562306a36Sopenharmony_ci "[ishtp-ish] Rx buffers pool is empty\n"); 47662306a36Sopenharmony_ci rets = -ENOMEM; 47762306a36Sopenharmony_ci rb = NULL; 47862306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 47962306a36Sopenharmony_ci goto out; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb, list); 48262306a36Sopenharmony_ci list_del_init(&rb->list); 48362306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci rb->cl = cl; 48662306a36Sopenharmony_ci rb->buf_idx = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci INIT_LIST_HEAD(&rb->list); 48962306a36Sopenharmony_ci rets = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * This must be BEFORE sending flow control - 49362306a36Sopenharmony_ci * response in ISR may come too fast... 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci spin_lock_irqsave(&dev->read_list_spinlock, dev_flags); 49662306a36Sopenharmony_ci list_add_tail(&rb->list, &dev->read_list.list); 49762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags); 49862306a36Sopenharmony_ci if (ishtp_hbm_cl_flow_control_req(dev, cl)) { 49962306a36Sopenharmony_ci rets = -ENODEV; 50062306a36Sopenharmony_ci goto out; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ciout: 50362306a36Sopenharmony_ci /* if ishtp_hbm_cl_flow_control_req failed, return rb to free list */ 50462306a36Sopenharmony_ci if (rets && rb) { 50562306a36Sopenharmony_ci spin_lock_irqsave(&dev->read_list_spinlock, dev_flags); 50662306a36Sopenharmony_ci list_del(&rb->list); 50762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci spin_lock_irqsave(&cl->free_list_spinlock, flags); 51062306a36Sopenharmony_ci list_add_tail(&rb->list, &cl->free_rb_list.list); 51162306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci return rets; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci/** 51762306a36Sopenharmony_ci * ishtp_cl_send() - Send a message to firmware 51862306a36Sopenharmony_ci * @cl: client device instance 51962306a36Sopenharmony_ci * @buf: message buffer 52062306a36Sopenharmony_ci * @length: length of message 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci * If the client is correct state to send message, this function gets a buffer 52362306a36Sopenharmony_ci * from tx ring buffers, copy the message data and call to send the message 52462306a36Sopenharmony_ci * using ishtp_cl_send_msg() 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * Return: 0 if successful or error code on failure 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ciint ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct ishtp_device *dev; 53162306a36Sopenharmony_ci int id; 53262306a36Sopenharmony_ci struct ishtp_cl_tx_ring *cl_msg; 53362306a36Sopenharmony_ci int have_msg_to_send = 0; 53462306a36Sopenharmony_ci unsigned long tx_flags, tx_free_flags; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (WARN_ON(!cl || !cl->dev)) 53762306a36Sopenharmony_ci return -ENODEV; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci dev = cl->dev; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (cl->state != ISHTP_CL_CONNECTED) { 54262306a36Sopenharmony_ci ++cl->err_send_msg; 54362306a36Sopenharmony_ci return -EPIPE; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) { 54762306a36Sopenharmony_ci ++cl->err_send_msg; 54862306a36Sopenharmony_ci return -ENODEV; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Check if we have fw client device */ 55262306a36Sopenharmony_ci id = ishtp_fw_cl_by_id(dev, cl->fw_client_id); 55362306a36Sopenharmony_ci if (id < 0) { 55462306a36Sopenharmony_ci ++cl->err_send_msg; 55562306a36Sopenharmony_ci return -ENOENT; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (length > dev->fw_clients[id].props.max_msg_length) { 55962306a36Sopenharmony_ci ++cl->err_send_msg; 56062306a36Sopenharmony_ci return -EMSGSIZE; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* No free bufs */ 56462306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 56562306a36Sopenharmony_ci if (list_empty(&cl->tx_free_list.list)) { 56662306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 56762306a36Sopenharmony_ci tx_free_flags); 56862306a36Sopenharmony_ci ++cl->err_send_msg; 56962306a36Sopenharmony_ci return -ENOMEM; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci cl_msg = list_first_entry(&cl->tx_free_list.list, 57362306a36Sopenharmony_ci struct ishtp_cl_tx_ring, list); 57462306a36Sopenharmony_ci if (!cl_msg->send_buf.data) { 57562306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 57662306a36Sopenharmony_ci tx_free_flags); 57762306a36Sopenharmony_ci return -EIO; 57862306a36Sopenharmony_ci /* Should not happen, as free list is pre-allocated */ 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci /* 58162306a36Sopenharmony_ci * This is safe, as 'length' is already checked for not exceeding 58262306a36Sopenharmony_ci * max ISHTP message size per client 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci list_del_init(&cl_msg->list); 58562306a36Sopenharmony_ci --cl->tx_ring_free_size; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 58862306a36Sopenharmony_ci memcpy(cl_msg->send_buf.data, buf, length); 58962306a36Sopenharmony_ci cl_msg->send_buf.size = length; 59062306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 59162306a36Sopenharmony_ci have_msg_to_send = !list_empty(&cl->tx_list.list); 59262306a36Sopenharmony_ci list_add_tail(&cl_msg->list, &cl->tx_list.list); 59362306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!have_msg_to_send && cl->ishtp_flow_ctrl_creds > 0) 59662306a36Sopenharmony_ci ishtp_cl_send_msg(dev, cl); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_send); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/** 60362306a36Sopenharmony_ci * ishtp_cl_read_complete() - read complete 60462306a36Sopenharmony_ci * @rb: Pointer to client request block 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * If the message is completely received call ishtp_cl_bus_rx_event() 60762306a36Sopenharmony_ci * to process message 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_cistatic void ishtp_cl_read_complete(struct ishtp_cl_rb *rb) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci unsigned long flags; 61262306a36Sopenharmony_ci int schedule_work_flag = 0; 61362306a36Sopenharmony_ci struct ishtp_cl *cl = rb->cl; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci spin_lock_irqsave(&cl->in_process_spinlock, flags); 61662306a36Sopenharmony_ci /* 61762306a36Sopenharmony_ci * if in-process list is empty, then need to schedule 61862306a36Sopenharmony_ci * the processing thread 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci schedule_work_flag = list_empty(&cl->in_process_list.list); 62162306a36Sopenharmony_ci list_add_tail(&rb->list, &cl->in_process_list.list); 62262306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->in_process_spinlock, flags); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (schedule_work_flag) 62562306a36Sopenharmony_ci ishtp_cl_bus_rx_event(cl->device); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/** 62962306a36Sopenharmony_ci * ipc_tx_send() - IPC tx send function 63062306a36Sopenharmony_ci * @prm: Pointer to client device instance 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Send message over IPC. Message will be split into fragments 63362306a36Sopenharmony_ci * if message size is bigger than IPC FIFO size, and all 63462306a36Sopenharmony_ci * fragments will be sent one by one. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_cistatic void ipc_tx_send(void *prm) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct ishtp_cl *cl = prm; 63962306a36Sopenharmony_ci struct ishtp_cl_tx_ring *cl_msg; 64062306a36Sopenharmony_ci size_t rem; 64162306a36Sopenharmony_ci struct ishtp_device *dev = (cl ? cl->dev : NULL); 64262306a36Sopenharmony_ci struct ishtp_msg_hdr ishtp_hdr; 64362306a36Sopenharmony_ci unsigned long tx_flags, tx_free_flags; 64462306a36Sopenharmony_ci unsigned char *pmsg; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (!dev) 64762306a36Sopenharmony_ci return; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * Other conditions if some critical error has 65162306a36Sopenharmony_ci * occurred before this callback is called 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci if (dev->dev_state != ISHTP_DEV_ENABLED) 65462306a36Sopenharmony_ci return; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (cl->state != ISHTP_CL_CONNECTED) 65762306a36Sopenharmony_ci return; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 66062306a36Sopenharmony_ci if (list_empty(&cl->tx_list.list)) { 66162306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 66262306a36Sopenharmony_ci return; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (cl->ishtp_flow_ctrl_creds != 1 && !cl->sending) { 66662306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 66762306a36Sopenharmony_ci return; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (!cl->sending) { 67162306a36Sopenharmony_ci --cl->ishtp_flow_ctrl_creds; 67262306a36Sopenharmony_ci cl->last_ipc_acked = 0; 67362306a36Sopenharmony_ci cl->last_tx_path = CL_TX_PATH_IPC; 67462306a36Sopenharmony_ci cl->sending = 1; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring, 67862306a36Sopenharmony_ci list); 67962306a36Sopenharmony_ci rem = cl_msg->send_buf.size - cl->tx_offs; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci while (rem > 0) { 68262306a36Sopenharmony_ci ishtp_hdr.host_addr = cl->host_client_id; 68362306a36Sopenharmony_ci ishtp_hdr.fw_addr = cl->fw_client_id; 68462306a36Sopenharmony_ci ishtp_hdr.reserved = 0; 68562306a36Sopenharmony_ci pmsg = cl_msg->send_buf.data + cl->tx_offs; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (rem <= dev->mtu) { 68862306a36Sopenharmony_ci /* Last fragment or only one packet */ 68962306a36Sopenharmony_ci ishtp_hdr.length = rem; 69062306a36Sopenharmony_ci ishtp_hdr.msg_complete = 1; 69162306a36Sopenharmony_ci /* Submit to IPC queue with no callback */ 69262306a36Sopenharmony_ci ishtp_write_message(dev, &ishtp_hdr, pmsg); 69362306a36Sopenharmony_ci cl->tx_offs = 0; 69462306a36Sopenharmony_ci cl->sending = 0; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } else { 69862306a36Sopenharmony_ci /* Send ipc fragment */ 69962306a36Sopenharmony_ci ishtp_hdr.length = dev->mtu; 70062306a36Sopenharmony_ci ishtp_hdr.msg_complete = 0; 70162306a36Sopenharmony_ci /* All fregments submitted to IPC queue with no callback */ 70262306a36Sopenharmony_ci ishtp_write_message(dev, &ishtp_hdr, pmsg); 70362306a36Sopenharmony_ci cl->tx_offs += dev->mtu; 70462306a36Sopenharmony_ci rem = cl_msg->send_buf.size - cl->tx_offs; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci list_del_init(&cl_msg->list); 70962306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 71262306a36Sopenharmony_ci list_add_tail(&cl_msg->list, &cl->tx_free_list.list); 71362306a36Sopenharmony_ci ++cl->tx_ring_free_size; 71462306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 71562306a36Sopenharmony_ci tx_free_flags); 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci/** 71962306a36Sopenharmony_ci * ishtp_cl_send_msg_ipc() -Send message using IPC 72062306a36Sopenharmony_ci * @dev: ISHTP device instance 72162306a36Sopenharmony_ci * @cl: Pointer to client device instance 72262306a36Sopenharmony_ci * 72362306a36Sopenharmony_ci * Send message over IPC not using DMA 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_cistatic void ishtp_cl_send_msg_ipc(struct ishtp_device *dev, 72662306a36Sopenharmony_ci struct ishtp_cl *cl) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci /* If last DMA message wasn't acked yet, leave this one in Tx queue */ 72962306a36Sopenharmony_ci if (cl->last_tx_path == CL_TX_PATH_DMA && cl->last_dma_acked == 0) 73062306a36Sopenharmony_ci return; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci cl->tx_offs = 0; 73362306a36Sopenharmony_ci ipc_tx_send(cl); 73462306a36Sopenharmony_ci ++cl->send_msg_cnt_ipc; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/** 73862306a36Sopenharmony_ci * ishtp_cl_send_msg_dma() -Send message using DMA 73962306a36Sopenharmony_ci * @dev: ISHTP device instance 74062306a36Sopenharmony_ci * @cl: Pointer to client device instance 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * Send message using DMA 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_cistatic void ishtp_cl_send_msg_dma(struct ishtp_device *dev, 74562306a36Sopenharmony_ci struct ishtp_cl *cl) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct ishtp_msg_hdr hdr; 74862306a36Sopenharmony_ci struct dma_xfer_hbm dma_xfer; 74962306a36Sopenharmony_ci unsigned char *msg_addr; 75062306a36Sopenharmony_ci int off; 75162306a36Sopenharmony_ci struct ishtp_cl_tx_ring *cl_msg; 75262306a36Sopenharmony_ci unsigned long tx_flags, tx_free_flags; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* If last IPC message wasn't acked yet, leave this one in Tx queue */ 75562306a36Sopenharmony_ci if (cl->last_tx_path == CL_TX_PATH_IPC && cl->last_ipc_acked == 0) 75662306a36Sopenharmony_ci return; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 75962306a36Sopenharmony_ci if (list_empty(&cl->tx_list.list)) { 76062306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 76162306a36Sopenharmony_ci return; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring, 76562306a36Sopenharmony_ci list); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci msg_addr = ishtp_cl_get_dma_send_buf(dev, cl_msg->send_buf.size); 76862306a36Sopenharmony_ci if (!msg_addr) { 76962306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 77062306a36Sopenharmony_ci if (dev->transfer_path == CL_TX_PATH_DEFAULT) 77162306a36Sopenharmony_ci ishtp_cl_send_msg_ipc(dev, cl); 77262306a36Sopenharmony_ci return; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci list_del_init(&cl_msg->list); /* Must be before write */ 77662306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci --cl->ishtp_flow_ctrl_creds; 77962306a36Sopenharmony_ci cl->last_dma_acked = 0; 78062306a36Sopenharmony_ci cl->last_dma_addr = msg_addr; 78162306a36Sopenharmony_ci cl->last_tx_path = CL_TX_PATH_DMA; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* write msg to dma buf */ 78462306a36Sopenharmony_ci memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* 78762306a36Sopenharmony_ci * if current fw don't support cache snooping, driver have to 78862306a36Sopenharmony_ci * flush the cache manually. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci if (dev->ops->dma_no_cache_snooping && 79162306a36Sopenharmony_ci dev->ops->dma_no_cache_snooping(dev)) 79262306a36Sopenharmony_ci clflush_cache_range(msg_addr, cl_msg->send_buf.size); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* send dma_xfer hbm msg */ 79562306a36Sopenharmony_ci off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf; 79662306a36Sopenharmony_ci ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm)); 79762306a36Sopenharmony_ci dma_xfer.hbm = DMA_XFER; 79862306a36Sopenharmony_ci dma_xfer.fw_client_id = cl->fw_client_id; 79962306a36Sopenharmony_ci dma_xfer.host_client_id = cl->host_client_id; 80062306a36Sopenharmony_ci dma_xfer.reserved = 0; 80162306a36Sopenharmony_ci dma_xfer.msg_addr = dev->ishtp_host_dma_tx_buf_phys + off; 80262306a36Sopenharmony_ci dma_xfer.msg_length = cl_msg->send_buf.size; 80362306a36Sopenharmony_ci dma_xfer.reserved2 = 0; 80462306a36Sopenharmony_ci ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer); 80562306a36Sopenharmony_ci spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 80662306a36Sopenharmony_ci list_add_tail(&cl_msg->list, &cl->tx_free_list.list); 80762306a36Sopenharmony_ci ++cl->tx_ring_free_size; 80862306a36Sopenharmony_ci spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 80962306a36Sopenharmony_ci ++cl->send_msg_cnt_dma; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/** 81362306a36Sopenharmony_ci * ishtp_cl_send_msg() -Send message using DMA or IPC 81462306a36Sopenharmony_ci * @dev: ISHTP device instance 81562306a36Sopenharmony_ci * @cl: Pointer to client device instance 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * Send message using DMA or IPC based on transfer_path 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_civoid ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci if (dev->transfer_path == CL_TX_PATH_DMA) 82262306a36Sopenharmony_ci ishtp_cl_send_msg_dma(dev, cl); 82362306a36Sopenharmony_ci else 82462306a36Sopenharmony_ci ishtp_cl_send_msg_ipc(dev, cl); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/** 82862306a36Sopenharmony_ci * recv_ishtp_cl_msg() -Receive client message 82962306a36Sopenharmony_ci * @dev: ISHTP device instance 83062306a36Sopenharmony_ci * @ishtp_hdr: Pointer to message header 83162306a36Sopenharmony_ci * 83262306a36Sopenharmony_ci * Receive and dispatch ISHTP client messages. This function executes in ISR 83362306a36Sopenharmony_ci * or work queue context 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_civoid recv_ishtp_cl_msg(struct ishtp_device *dev, 83662306a36Sopenharmony_ci struct ishtp_msg_hdr *ishtp_hdr) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct ishtp_cl *cl; 83962306a36Sopenharmony_ci struct ishtp_cl_rb *rb; 84062306a36Sopenharmony_ci struct ishtp_cl_rb *new_rb; 84162306a36Sopenharmony_ci unsigned char *buffer = NULL; 84262306a36Sopenharmony_ci struct ishtp_cl_rb *complete_rb = NULL; 84362306a36Sopenharmony_ci unsigned long flags; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (ishtp_hdr->reserved) { 84662306a36Sopenharmony_ci dev_err(dev->devc, "corrupted message header.\n"); 84762306a36Sopenharmony_ci goto eoi; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (ishtp_hdr->length > IPC_PAYLOAD_SIZE) { 85162306a36Sopenharmony_ci dev_err(dev->devc, 85262306a36Sopenharmony_ci "ISHTP message length in hdr exceeds IPC MTU\n"); 85362306a36Sopenharmony_ci goto eoi; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci spin_lock_irqsave(&dev->read_list_spinlock, flags); 85762306a36Sopenharmony_ci list_for_each_entry(rb, &dev->read_list.list, list) { 85862306a36Sopenharmony_ci cl = rb->cl; 85962306a36Sopenharmony_ci if (!cl || !(cl->host_client_id == ishtp_hdr->host_addr && 86062306a36Sopenharmony_ci cl->fw_client_id == ishtp_hdr->fw_addr) || 86162306a36Sopenharmony_ci !(cl->state == ISHTP_CL_CONNECTED)) 86262306a36Sopenharmony_ci continue; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* If no Rx buffer is allocated, disband the rb */ 86562306a36Sopenharmony_ci if (rb->buffer.size == 0 || rb->buffer.data == NULL) { 86662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 86762306a36Sopenharmony_ci dev_err(&cl->device->dev, 86862306a36Sopenharmony_ci "Rx buffer is not allocated.\n"); 86962306a36Sopenharmony_ci list_del(&rb->list); 87062306a36Sopenharmony_ci ishtp_io_rb_free(rb); 87162306a36Sopenharmony_ci cl->status = -ENOMEM; 87262306a36Sopenharmony_ci goto eoi; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* 87662306a36Sopenharmony_ci * If message buffer overflown (exceeds max. client msg 87762306a36Sopenharmony_ci * size, drop message and return to free buffer. 87862306a36Sopenharmony_ci * Do we need to disconnect such a client? (We don't send 87962306a36Sopenharmony_ci * back FC, so communication will be stuck anyway) 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci if (rb->buffer.size < ishtp_hdr->length + rb->buf_idx) { 88262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 88362306a36Sopenharmony_ci dev_err(&cl->device->dev, 88462306a36Sopenharmony_ci "message overflow. size %d len %d idx %ld\n", 88562306a36Sopenharmony_ci rb->buffer.size, ishtp_hdr->length, 88662306a36Sopenharmony_ci rb->buf_idx); 88762306a36Sopenharmony_ci list_del(&rb->list); 88862306a36Sopenharmony_ci ishtp_cl_io_rb_recycle(rb); 88962306a36Sopenharmony_ci cl->status = -EIO; 89062306a36Sopenharmony_ci goto eoi; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci buffer = rb->buffer.data + rb->buf_idx; 89462306a36Sopenharmony_ci dev->ops->ishtp_read(dev, buffer, ishtp_hdr->length); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci rb->buf_idx += ishtp_hdr->length; 89762306a36Sopenharmony_ci if (ishtp_hdr->msg_complete) { 89862306a36Sopenharmony_ci /* Last fragment in message - it's complete */ 89962306a36Sopenharmony_ci cl->status = 0; 90062306a36Sopenharmony_ci list_del(&rb->list); 90162306a36Sopenharmony_ci complete_rb = rb; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci --cl->out_flow_ctrl_creds; 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * the whole msg arrived, send a new FC, and add a new 90662306a36Sopenharmony_ci * rb buffer for the next coming msg 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci spin_lock(&cl->free_list_spinlock); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (!list_empty(&cl->free_rb_list.list)) { 91162306a36Sopenharmony_ci new_rb = list_entry(cl->free_rb_list.list.next, 91262306a36Sopenharmony_ci struct ishtp_cl_rb, list); 91362306a36Sopenharmony_ci list_del_init(&new_rb->list); 91462306a36Sopenharmony_ci spin_unlock(&cl->free_list_spinlock); 91562306a36Sopenharmony_ci new_rb->cl = cl; 91662306a36Sopenharmony_ci new_rb->buf_idx = 0; 91762306a36Sopenharmony_ci INIT_LIST_HEAD(&new_rb->list); 91862306a36Sopenharmony_ci list_add_tail(&new_rb->list, 91962306a36Sopenharmony_ci &dev->read_list.list); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ishtp_hbm_cl_flow_control_req(dev, cl); 92262306a36Sopenharmony_ci } else { 92362306a36Sopenharmony_ci spin_unlock(&cl->free_list_spinlock); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci /* One more fragment in message (even if this was last) */ 92762306a36Sopenharmony_ci ++cl->recv_msg_num_frags; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * We can safely break here (and in BH too), 93162306a36Sopenharmony_ci * a single input message can go only to a single request! 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 93762306a36Sopenharmony_ci /* If it's nobody's message, just read and discard it */ 93862306a36Sopenharmony_ci if (!buffer) { 93962306a36Sopenharmony_ci uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE]; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci dev_err(dev->devc, "Dropped Rx msg - no request\n"); 94262306a36Sopenharmony_ci dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length); 94362306a36Sopenharmony_ci goto eoi; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (complete_rb) { 94762306a36Sopenharmony_ci cl = complete_rb->cl; 94862306a36Sopenharmony_ci cl->ts_rx = ktime_get(); 94962306a36Sopenharmony_ci ++cl->recv_msg_cnt_ipc; 95062306a36Sopenharmony_ci ishtp_cl_read_complete(complete_rb); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_cieoi: 95362306a36Sopenharmony_ci return; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/** 95762306a36Sopenharmony_ci * recv_ishtp_cl_msg_dma() -Receive client message 95862306a36Sopenharmony_ci * @dev: ISHTP device instance 95962306a36Sopenharmony_ci * @msg: message pointer 96062306a36Sopenharmony_ci * @hbm: hbm buffer 96162306a36Sopenharmony_ci * 96262306a36Sopenharmony_ci * Receive and dispatch ISHTP client messages using DMA. This function executes 96362306a36Sopenharmony_ci * in ISR or work queue context 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_civoid recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg, 96662306a36Sopenharmony_ci struct dma_xfer_hbm *hbm) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct ishtp_cl *cl; 96962306a36Sopenharmony_ci struct ishtp_cl_rb *rb; 97062306a36Sopenharmony_ci struct ishtp_cl_rb *new_rb; 97162306a36Sopenharmony_ci unsigned char *buffer = NULL; 97262306a36Sopenharmony_ci struct ishtp_cl_rb *complete_rb = NULL; 97362306a36Sopenharmony_ci unsigned long flags; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci spin_lock_irqsave(&dev->read_list_spinlock, flags); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci list_for_each_entry(rb, &dev->read_list.list, list) { 97862306a36Sopenharmony_ci cl = rb->cl; 97962306a36Sopenharmony_ci if (!cl || !(cl->host_client_id == hbm->host_client_id && 98062306a36Sopenharmony_ci cl->fw_client_id == hbm->fw_client_id) || 98162306a36Sopenharmony_ci !(cl->state == ISHTP_CL_CONNECTED)) 98262306a36Sopenharmony_ci continue; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* 98562306a36Sopenharmony_ci * If no Rx buffer is allocated, disband the rb 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci if (rb->buffer.size == 0 || rb->buffer.data == NULL) { 98862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 98962306a36Sopenharmony_ci dev_err(&cl->device->dev, 99062306a36Sopenharmony_ci "response buffer is not allocated.\n"); 99162306a36Sopenharmony_ci list_del(&rb->list); 99262306a36Sopenharmony_ci ishtp_io_rb_free(rb); 99362306a36Sopenharmony_ci cl->status = -ENOMEM; 99462306a36Sopenharmony_ci goto eoi; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* 99862306a36Sopenharmony_ci * If message buffer overflown (exceeds max. client msg 99962306a36Sopenharmony_ci * size, drop message and return to free buffer. 100062306a36Sopenharmony_ci * Do we need to disconnect such a client? (We don't send 100162306a36Sopenharmony_ci * back FC, so communication will be stuck anyway) 100262306a36Sopenharmony_ci */ 100362306a36Sopenharmony_ci if (rb->buffer.size < hbm->msg_length) { 100462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 100562306a36Sopenharmony_ci dev_err(&cl->device->dev, 100662306a36Sopenharmony_ci "message overflow. size %d len %d idx %ld\n", 100762306a36Sopenharmony_ci rb->buffer.size, hbm->msg_length, rb->buf_idx); 100862306a36Sopenharmony_ci list_del(&rb->list); 100962306a36Sopenharmony_ci ishtp_cl_io_rb_recycle(rb); 101062306a36Sopenharmony_ci cl->status = -EIO; 101162306a36Sopenharmony_ci goto eoi; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci buffer = rb->buffer.data; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* 101762306a36Sopenharmony_ci * if current fw don't support cache snooping, driver have to 101862306a36Sopenharmony_ci * flush the cache manually. 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ci if (dev->ops->dma_no_cache_snooping && 102162306a36Sopenharmony_ci dev->ops->dma_no_cache_snooping(dev)) 102262306a36Sopenharmony_ci clflush_cache_range(msg, hbm->msg_length); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci memcpy(buffer, msg, hbm->msg_length); 102562306a36Sopenharmony_ci rb->buf_idx = hbm->msg_length; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* Last fragment in message - it's complete */ 102862306a36Sopenharmony_ci cl->status = 0; 102962306a36Sopenharmony_ci list_del(&rb->list); 103062306a36Sopenharmony_ci complete_rb = rb; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci --cl->out_flow_ctrl_creds; 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * the whole msg arrived, send a new FC, and add a new 103562306a36Sopenharmony_ci * rb buffer for the next coming msg 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_ci spin_lock(&cl->free_list_spinlock); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (!list_empty(&cl->free_rb_list.list)) { 104062306a36Sopenharmony_ci new_rb = list_entry(cl->free_rb_list.list.next, 104162306a36Sopenharmony_ci struct ishtp_cl_rb, list); 104262306a36Sopenharmony_ci list_del_init(&new_rb->list); 104362306a36Sopenharmony_ci spin_unlock(&cl->free_list_spinlock); 104462306a36Sopenharmony_ci new_rb->cl = cl; 104562306a36Sopenharmony_ci new_rb->buf_idx = 0; 104662306a36Sopenharmony_ci INIT_LIST_HEAD(&new_rb->list); 104762306a36Sopenharmony_ci list_add_tail(&new_rb->list, 104862306a36Sopenharmony_ci &dev->read_list.list); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci ishtp_hbm_cl_flow_control_req(dev, cl); 105162306a36Sopenharmony_ci } else { 105262306a36Sopenharmony_ci spin_unlock(&cl->free_list_spinlock); 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* One more fragment in message (this is always last) */ 105662306a36Sopenharmony_ci ++cl->recv_msg_num_frags; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* 105962306a36Sopenharmony_ci * We can safely break here (and in BH too), 106062306a36Sopenharmony_ci * a single input message can go only to a single request! 106162306a36Sopenharmony_ci */ 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 106662306a36Sopenharmony_ci /* If it's nobody's message, just read and discard it */ 106762306a36Sopenharmony_ci if (!buffer) { 106862306a36Sopenharmony_ci dev_err(dev->devc, "Dropped Rx (DMA) msg - no request\n"); 106962306a36Sopenharmony_ci goto eoi; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (complete_rb) { 107362306a36Sopenharmony_ci cl = complete_rb->cl; 107462306a36Sopenharmony_ci cl->ts_rx = ktime_get(); 107562306a36Sopenharmony_ci ++cl->recv_msg_cnt_dma; 107662306a36Sopenharmony_ci ishtp_cl_read_complete(complete_rb); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_cieoi: 107962306a36Sopenharmony_ci return; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_civoid *ishtp_get_client_data(struct ishtp_cl *cl) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci return cl->client_data; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_get_client_data); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_civoid ishtp_set_client_data(struct ishtp_cl *cl, void *data) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci cl->client_data = data; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_set_client_data); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistruct ishtp_device *ishtp_get_ishtp_device(struct ishtp_cl *cl) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci return cl->dev; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_get_ishtp_device); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_civoid ishtp_set_tx_ring_size(struct ishtp_cl *cl, int size) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci cl->tx_ring_size = size; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_set_tx_ring_size); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_civoid ishtp_set_rx_ring_size(struct ishtp_cl *cl, int size) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci cl->rx_ring_size = size; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_set_rx_ring_size); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_civoid ishtp_set_connection_state(struct ishtp_cl *cl, int state) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci cl->state = state; 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_set_connection_state); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_civoid ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci cl->fw_client_id = fw_client_id; 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ciEXPORT_SYMBOL(ishtp_cl_set_fw_client_id); 1123