12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23703f53bSSrinivas Pandruvada /* 33703f53bSSrinivas Pandruvada * ISHTP client logic 43703f53bSSrinivas Pandruvada * 53703f53bSSrinivas Pandruvada * Copyright (c) 2003-2016, Intel Corporation. 63703f53bSSrinivas Pandruvada */ 73703f53bSSrinivas Pandruvada 83703f53bSSrinivas Pandruvada #include <linux/slab.h> 93703f53bSSrinivas Pandruvada #include <linux/sched.h> 103703f53bSSrinivas Pandruvada #include <linux/wait.h> 113703f53bSSrinivas Pandruvada #include <linux/delay.h> 123703f53bSSrinivas Pandruvada #include <linux/dma-mapping.h> 133703f53bSSrinivas Pandruvada #include "hbm.h" 143703f53bSSrinivas Pandruvada #include "client.h" 153703f53bSSrinivas Pandruvada 1618c0b546SSrinivas Pandruvada int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl) 1718c0b546SSrinivas Pandruvada { 1818c0b546SSrinivas Pandruvada unsigned long tx_free_flags; 1918c0b546SSrinivas Pandruvada int size; 2018c0b546SSrinivas Pandruvada 2118c0b546SSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 2218c0b546SSrinivas Pandruvada size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length; 2318c0b546SSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 2418c0b546SSrinivas Pandruvada 2518c0b546SSrinivas Pandruvada return size; 2618c0b546SSrinivas Pandruvada } 2718c0b546SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size); 2818c0b546SSrinivas Pandruvada 2918c0b546SSrinivas Pandruvada int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl) 3018c0b546SSrinivas Pandruvada { 3118c0b546SSrinivas Pandruvada return cl->tx_ring_free_size; 3218c0b546SSrinivas Pandruvada } 3318c0b546SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_get_tx_free_rings); 3418c0b546SSrinivas Pandruvada 353703f53bSSrinivas Pandruvada /** 363703f53bSSrinivas Pandruvada * ishtp_read_list_flush() - Flush read queue 373703f53bSSrinivas Pandruvada * @cl: ishtp client instance 383703f53bSSrinivas Pandruvada * 393703f53bSSrinivas Pandruvada * Used to remove all entries from read queue for a client 403703f53bSSrinivas Pandruvada */ 413703f53bSSrinivas Pandruvada static void ishtp_read_list_flush(struct ishtp_cl *cl) 423703f53bSSrinivas Pandruvada { 433703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb; 443703f53bSSrinivas Pandruvada struct ishtp_cl_rb *next; 453703f53bSSrinivas Pandruvada unsigned long flags; 463703f53bSSrinivas Pandruvada 473703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->dev->read_list_spinlock, flags); 483703f53bSSrinivas Pandruvada list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list) 493703f53bSSrinivas Pandruvada if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) { 503703f53bSSrinivas Pandruvada list_del(&rb->list); 513703f53bSSrinivas Pandruvada ishtp_io_rb_free(rb); 523703f53bSSrinivas Pandruvada } 533703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags); 543703f53bSSrinivas Pandruvada } 553703f53bSSrinivas Pandruvada 563703f53bSSrinivas Pandruvada /** 573703f53bSSrinivas Pandruvada * ishtp_cl_flush_queues() - Flush all queues for a client 583703f53bSSrinivas Pandruvada * @cl: ishtp client instance 593703f53bSSrinivas Pandruvada * 603703f53bSSrinivas Pandruvada * Used to remove all queues for a client. This is called when a client device 613703f53bSSrinivas Pandruvada * needs reset due to error, S3 resume or during module removal 623703f53bSSrinivas Pandruvada * 633703f53bSSrinivas Pandruvada * Return: 0 on success else -EINVAL if device is NULL 643703f53bSSrinivas Pandruvada */ 653703f53bSSrinivas Pandruvada int ishtp_cl_flush_queues(struct ishtp_cl *cl) 663703f53bSSrinivas Pandruvada { 673703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 683703f53bSSrinivas Pandruvada return -EINVAL; 693703f53bSSrinivas Pandruvada 703703f53bSSrinivas Pandruvada ishtp_read_list_flush(cl); 713703f53bSSrinivas Pandruvada 723703f53bSSrinivas Pandruvada return 0; 733703f53bSSrinivas Pandruvada } 743703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_flush_queues); 753703f53bSSrinivas Pandruvada 763703f53bSSrinivas Pandruvada /** 773703f53bSSrinivas Pandruvada * ishtp_cl_init() - Initialize all fields of a client device 783703f53bSSrinivas Pandruvada * @cl: ishtp client instance 793703f53bSSrinivas Pandruvada * @dev: ishtp device 803703f53bSSrinivas Pandruvada * 813703f53bSSrinivas Pandruvada * Initializes a client device fields: Init spinlocks, init queues etc. 823703f53bSSrinivas Pandruvada * This function is called during new client creation 833703f53bSSrinivas Pandruvada */ 843703f53bSSrinivas Pandruvada static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev) 853703f53bSSrinivas Pandruvada { 863703f53bSSrinivas Pandruvada memset(cl, 0, sizeof(struct ishtp_cl)); 873703f53bSSrinivas Pandruvada init_waitqueue_head(&cl->wait_ctrl_res); 883703f53bSSrinivas Pandruvada spin_lock_init(&cl->free_list_spinlock); 893703f53bSSrinivas Pandruvada spin_lock_init(&cl->in_process_spinlock); 903703f53bSSrinivas Pandruvada spin_lock_init(&cl->tx_list_spinlock); 913703f53bSSrinivas Pandruvada spin_lock_init(&cl->tx_free_list_spinlock); 923703f53bSSrinivas Pandruvada spin_lock_init(&cl->fc_spinlock); 933703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&cl->link); 943703f53bSSrinivas Pandruvada cl->dev = dev; 953703f53bSSrinivas Pandruvada 963703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&cl->free_rb_list.list); 973703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&cl->tx_list.list); 983703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&cl->tx_free_list.list); 993703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&cl->in_process_list.list); 1003703f53bSSrinivas Pandruvada 1013703f53bSSrinivas Pandruvada cl->rx_ring_size = CL_DEF_RX_RING_SIZE; 1023703f53bSSrinivas Pandruvada cl->tx_ring_size = CL_DEF_TX_RING_SIZE; 10318c0b546SSrinivas Pandruvada cl->tx_ring_free_size = cl->tx_ring_size; 1043703f53bSSrinivas Pandruvada 1053703f53bSSrinivas Pandruvada /* dma */ 1063703f53bSSrinivas Pandruvada cl->last_tx_path = CL_TX_PATH_IPC; 1073703f53bSSrinivas Pandruvada cl->last_dma_acked = 1; 1083703f53bSSrinivas Pandruvada cl->last_dma_addr = NULL; 1093703f53bSSrinivas Pandruvada cl->last_ipc_acked = 1; 1103703f53bSSrinivas Pandruvada } 1113703f53bSSrinivas Pandruvada 1123703f53bSSrinivas Pandruvada /** 1133703f53bSSrinivas Pandruvada * ishtp_cl_allocate() - allocates client structure and sets it up. 1143703f53bSSrinivas Pandruvada * @dev: ishtp device 1153703f53bSSrinivas Pandruvada * 1163703f53bSSrinivas Pandruvada * Allocate memory for new client device and call to initialize each field. 1173703f53bSSrinivas Pandruvada * 1183703f53bSSrinivas Pandruvada * Return: The allocated client instance or NULL on failure 1193703f53bSSrinivas Pandruvada */ 1207ab21842SSrinivas Pandruvada struct ishtp_cl *ishtp_cl_allocate(struct ishtp_cl_device *cl_device) 1213703f53bSSrinivas Pandruvada { 1223703f53bSSrinivas Pandruvada struct ishtp_cl *cl; 1233703f53bSSrinivas Pandruvada 1243703f53bSSrinivas Pandruvada cl = kmalloc(sizeof(struct ishtp_cl), GFP_KERNEL); 1253703f53bSSrinivas Pandruvada if (!cl) 1263703f53bSSrinivas Pandruvada return NULL; 1273703f53bSSrinivas Pandruvada 1287ab21842SSrinivas Pandruvada ishtp_cl_init(cl, cl_device->ishtp_dev); 1293703f53bSSrinivas Pandruvada return cl; 1303703f53bSSrinivas Pandruvada } 1313703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_allocate); 1323703f53bSSrinivas Pandruvada 1333703f53bSSrinivas Pandruvada /** 1343703f53bSSrinivas Pandruvada * ishtp_cl_free() - Frees a client device 1353703f53bSSrinivas Pandruvada * @cl: client device instance 1363703f53bSSrinivas Pandruvada * 1373703f53bSSrinivas Pandruvada * Frees a client device 1383703f53bSSrinivas Pandruvada */ 1393703f53bSSrinivas Pandruvada void ishtp_cl_free(struct ishtp_cl *cl) 1403703f53bSSrinivas Pandruvada { 1413703f53bSSrinivas Pandruvada struct ishtp_device *dev; 1423703f53bSSrinivas Pandruvada unsigned long flags; 1433703f53bSSrinivas Pandruvada 1443703f53bSSrinivas Pandruvada if (!cl) 1453703f53bSSrinivas Pandruvada return; 1463703f53bSSrinivas Pandruvada 1473703f53bSSrinivas Pandruvada dev = cl->dev; 1483703f53bSSrinivas Pandruvada if (!dev) 1493703f53bSSrinivas Pandruvada return; 1503703f53bSSrinivas Pandruvada 1513703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->cl_list_lock, flags); 1523703f53bSSrinivas Pandruvada ishtp_cl_free_rx_ring(cl); 1533703f53bSSrinivas Pandruvada ishtp_cl_free_tx_ring(cl); 1543703f53bSSrinivas Pandruvada kfree(cl); 1553703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->cl_list_lock, flags); 1563703f53bSSrinivas Pandruvada } 1573703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_free); 1583703f53bSSrinivas Pandruvada 1593703f53bSSrinivas Pandruvada /** 1603703f53bSSrinivas Pandruvada * ishtp_cl_link() - Reserve a host id and link the client instance 1613703f53bSSrinivas Pandruvada * @cl: client device instance 1623703f53bSSrinivas Pandruvada * 1633703f53bSSrinivas Pandruvada * This allocates a single bit in the hostmap. This function will make sure 1643703f53bSSrinivas Pandruvada * that not many client sessions are opened at the same time. Once allocated 1653703f53bSSrinivas Pandruvada * the client device instance is added to the ishtp device in the current 1663703f53bSSrinivas Pandruvada * client list 1673703f53bSSrinivas Pandruvada * 1683703f53bSSrinivas Pandruvada * Return: 0 or error code on failure 1693703f53bSSrinivas Pandruvada */ 170c2012ec0SSrinivas Pandruvada int ishtp_cl_link(struct ishtp_cl *cl) 1713703f53bSSrinivas Pandruvada { 1723703f53bSSrinivas Pandruvada struct ishtp_device *dev; 1733703f53bSSrinivas Pandruvada unsigned long flags, flags_cl; 174c2012ec0SSrinivas Pandruvada int id, ret = 0; 1753703f53bSSrinivas Pandruvada 1763703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 1773703f53bSSrinivas Pandruvada return -EINVAL; 1783703f53bSSrinivas Pandruvada 1793703f53bSSrinivas Pandruvada dev = cl->dev; 1803703f53bSSrinivas Pandruvada 1813703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->device_lock, flags); 1823703f53bSSrinivas Pandruvada 1833703f53bSSrinivas Pandruvada if (dev->open_handle_count >= ISHTP_MAX_OPEN_HANDLE_COUNT) { 1843703f53bSSrinivas Pandruvada ret = -EMFILE; 1853703f53bSSrinivas Pandruvada goto unlock_dev; 1863703f53bSSrinivas Pandruvada } 1873703f53bSSrinivas Pandruvada 188c2012ec0SSrinivas Pandruvada id = find_first_zero_bit(dev->host_clients_map, ISHTP_CLIENTS_MAX); 1893703f53bSSrinivas Pandruvada 1903703f53bSSrinivas Pandruvada if (id >= ISHTP_CLIENTS_MAX) { 1913703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_lock, flags); 1923703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, "id exceeded %d", ISHTP_CLIENTS_MAX); 1933703f53bSSrinivas Pandruvada return -ENOENT; 1943703f53bSSrinivas Pandruvada } 1953703f53bSSrinivas Pandruvada 1963703f53bSSrinivas Pandruvada dev->open_handle_count++; 1973703f53bSSrinivas Pandruvada cl->host_client_id = id; 1983703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->cl_list_lock, flags_cl); 1993703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) { 2003703f53bSSrinivas Pandruvada ret = -ENODEV; 2013703f53bSSrinivas Pandruvada goto unlock_cl; 2023703f53bSSrinivas Pandruvada } 2033703f53bSSrinivas Pandruvada list_add_tail(&cl->link, &dev->cl_list); 2043703f53bSSrinivas Pandruvada set_bit(id, dev->host_clients_map); 2053703f53bSSrinivas Pandruvada cl->state = ISHTP_CL_INITIALIZING; 2063703f53bSSrinivas Pandruvada 2073703f53bSSrinivas Pandruvada unlock_cl: 2083703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->cl_list_lock, flags_cl); 2093703f53bSSrinivas Pandruvada unlock_dev: 2103703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_lock, flags); 2113703f53bSSrinivas Pandruvada return ret; 2123703f53bSSrinivas Pandruvada } 2133703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_link); 2143703f53bSSrinivas Pandruvada 2153703f53bSSrinivas Pandruvada /** 2163703f53bSSrinivas Pandruvada * ishtp_cl_unlink() - remove fw_cl from the client device list 2173703f53bSSrinivas Pandruvada * @cl: client device instance 2183703f53bSSrinivas Pandruvada * 2193703f53bSSrinivas Pandruvada * Remove a previously linked device to a ishtp device 2203703f53bSSrinivas Pandruvada */ 2213703f53bSSrinivas Pandruvada void ishtp_cl_unlink(struct ishtp_cl *cl) 2223703f53bSSrinivas Pandruvada { 2233703f53bSSrinivas Pandruvada struct ishtp_device *dev; 2243703f53bSSrinivas Pandruvada struct ishtp_cl *pos; 2253703f53bSSrinivas Pandruvada unsigned long flags; 2263703f53bSSrinivas Pandruvada 2273703f53bSSrinivas Pandruvada /* don't shout on error exit path */ 2283703f53bSSrinivas Pandruvada if (!cl || !cl->dev) 2293703f53bSSrinivas Pandruvada return; 2303703f53bSSrinivas Pandruvada 2313703f53bSSrinivas Pandruvada dev = cl->dev; 2323703f53bSSrinivas Pandruvada 2333703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->device_lock, flags); 2343703f53bSSrinivas Pandruvada if (dev->open_handle_count > 0) { 2353703f53bSSrinivas Pandruvada clear_bit(cl->host_client_id, dev->host_clients_map); 2363703f53bSSrinivas Pandruvada dev->open_handle_count--; 2373703f53bSSrinivas Pandruvada } 2383703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_lock, flags); 2393703f53bSSrinivas Pandruvada 2403703f53bSSrinivas Pandruvada /* 2413703f53bSSrinivas Pandruvada * This checks that 'cl' is actually linked into device's structure, 2423703f53bSSrinivas Pandruvada * before attempting 'list_del' 2433703f53bSSrinivas Pandruvada */ 2443703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->cl_list_lock, flags); 2453703f53bSSrinivas Pandruvada list_for_each_entry(pos, &dev->cl_list, link) 2463703f53bSSrinivas Pandruvada if (cl->host_client_id == pos->host_client_id) { 2473703f53bSSrinivas Pandruvada list_del_init(&pos->link); 2483703f53bSSrinivas Pandruvada break; 2493703f53bSSrinivas Pandruvada } 2503703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->cl_list_lock, flags); 2513703f53bSSrinivas Pandruvada } 2523703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_unlink); 2533703f53bSSrinivas Pandruvada 2543703f53bSSrinivas Pandruvada /** 2553703f53bSSrinivas Pandruvada * ishtp_cl_disconnect() - Send disconnect request to firmware 2563703f53bSSrinivas Pandruvada * @cl: client device instance 2573703f53bSSrinivas Pandruvada * 2583703f53bSSrinivas Pandruvada * Send a disconnect request for a client to firmware. 2593703f53bSSrinivas Pandruvada * 2603703f53bSSrinivas Pandruvada * Return: 0 if successful disconnect response from the firmware or error 2613703f53bSSrinivas Pandruvada * code on failure 2623703f53bSSrinivas Pandruvada */ 2633703f53bSSrinivas Pandruvada int ishtp_cl_disconnect(struct ishtp_cl *cl) 2643703f53bSSrinivas Pandruvada { 2653703f53bSSrinivas Pandruvada struct ishtp_device *dev; 2663703f53bSSrinivas Pandruvada int err; 2673703f53bSSrinivas Pandruvada 2683703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 2693703f53bSSrinivas Pandruvada return -ENODEV; 2703703f53bSSrinivas Pandruvada 2713703f53bSSrinivas Pandruvada dev = cl->dev; 2723703f53bSSrinivas Pandruvada 2733703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() state %d\n", __func__, cl->state); 2743703f53bSSrinivas Pandruvada 2753703f53bSSrinivas Pandruvada if (cl->state != ISHTP_CL_DISCONNECTING) { 2763703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Disconnect in progress\n", __func__); 2773703f53bSSrinivas Pandruvada return 0; 2783703f53bSSrinivas Pandruvada } 2793703f53bSSrinivas Pandruvada 2803703f53bSSrinivas Pandruvada if (ishtp_hbm_cl_disconnect_req(dev, cl)) { 2813703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Failed to disconnect\n", __func__); 2823703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, "failed to disconnect.\n"); 2833703f53bSSrinivas Pandruvada return -ENODEV; 2843703f53bSSrinivas Pandruvada } 2853703f53bSSrinivas Pandruvada 2863703f53bSSrinivas Pandruvada err = wait_event_interruptible_timeout(cl->wait_ctrl_res, 2873703f53bSSrinivas Pandruvada (dev->dev_state != ISHTP_DEV_ENABLED || 2883703f53bSSrinivas Pandruvada cl->state == ISHTP_CL_DISCONNECTED), 2893703f53bSSrinivas Pandruvada ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT)); 2903703f53bSSrinivas Pandruvada 2913703f53bSSrinivas Pandruvada /* 2923703f53bSSrinivas Pandruvada * If FW reset arrived, this will happen. Don't check cl->, 2933703f53bSSrinivas Pandruvada * as 'cl' may be freed already 2943703f53bSSrinivas Pandruvada */ 2953703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) { 2963703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n", 2973703f53bSSrinivas Pandruvada __func__); 2983703f53bSSrinivas Pandruvada return -ENODEV; 2993703f53bSSrinivas Pandruvada } 3003703f53bSSrinivas Pandruvada 3013703f53bSSrinivas Pandruvada if (cl->state == ISHTP_CL_DISCONNECTED) { 3023703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() successful\n", __func__); 3033703f53bSSrinivas Pandruvada return 0; 3043703f53bSSrinivas Pandruvada } 3053703f53bSSrinivas Pandruvada 3063703f53bSSrinivas Pandruvada return -ENODEV; 3073703f53bSSrinivas Pandruvada } 3083703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_disconnect); 3093703f53bSSrinivas Pandruvada 3103703f53bSSrinivas Pandruvada /** 3113703f53bSSrinivas Pandruvada * ishtp_cl_is_other_connecting() - Check other client is connecting 3123703f53bSSrinivas Pandruvada * @cl: client device instance 3133703f53bSSrinivas Pandruvada * 3143703f53bSSrinivas Pandruvada * Checks if other client with the same fw client id is connecting 3153703f53bSSrinivas Pandruvada * 3163703f53bSSrinivas Pandruvada * Return: true if other client is connected else false 3173703f53bSSrinivas Pandruvada */ 3183703f53bSSrinivas Pandruvada static bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl) 3193703f53bSSrinivas Pandruvada { 3203703f53bSSrinivas Pandruvada struct ishtp_device *dev; 3213703f53bSSrinivas Pandruvada struct ishtp_cl *pos; 3223703f53bSSrinivas Pandruvada unsigned long flags; 3233703f53bSSrinivas Pandruvada 3243703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 3253703f53bSSrinivas Pandruvada return false; 3263703f53bSSrinivas Pandruvada 3273703f53bSSrinivas Pandruvada dev = cl->dev; 3283703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->cl_list_lock, flags); 3293703f53bSSrinivas Pandruvada list_for_each_entry(pos, &dev->cl_list, link) { 3303703f53bSSrinivas Pandruvada if ((pos->state == ISHTP_CL_CONNECTING) && (pos != cl) && 3313703f53bSSrinivas Pandruvada cl->fw_client_id == pos->fw_client_id) { 3323703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->cl_list_lock, flags); 3333703f53bSSrinivas Pandruvada return true; 3343703f53bSSrinivas Pandruvada } 3353703f53bSSrinivas Pandruvada } 3363703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->cl_list_lock, flags); 3373703f53bSSrinivas Pandruvada 3383703f53bSSrinivas Pandruvada return false; 3393703f53bSSrinivas Pandruvada } 3403703f53bSSrinivas Pandruvada 3413703f53bSSrinivas Pandruvada /** 3423703f53bSSrinivas Pandruvada * ishtp_cl_connect() - Send connect request to firmware 3433703f53bSSrinivas Pandruvada * @cl: client device instance 3443703f53bSSrinivas Pandruvada * 3453703f53bSSrinivas Pandruvada * Send a connect request for a client to firmware. If successful it will 3463703f53bSSrinivas Pandruvada * RX and TX ring buffers 3473703f53bSSrinivas Pandruvada * 3483703f53bSSrinivas Pandruvada * Return: 0 if successful connect response from the firmware and able 3493703f53bSSrinivas Pandruvada * to bind and allocate ring buffers or error code on failure 3503703f53bSSrinivas Pandruvada */ 3513703f53bSSrinivas Pandruvada int ishtp_cl_connect(struct ishtp_cl *cl) 3523703f53bSSrinivas Pandruvada { 3533703f53bSSrinivas Pandruvada struct ishtp_device *dev; 3543703f53bSSrinivas Pandruvada int rets; 3553703f53bSSrinivas Pandruvada 3563703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 3573703f53bSSrinivas Pandruvada return -ENODEV; 3583703f53bSSrinivas Pandruvada 3593703f53bSSrinivas Pandruvada dev = cl->dev; 3603703f53bSSrinivas Pandruvada 3613703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state); 3623703f53bSSrinivas Pandruvada 3633703f53bSSrinivas Pandruvada if (ishtp_cl_is_other_connecting(cl)) { 3643703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Busy\n", __func__); 3653703f53bSSrinivas Pandruvada return -EBUSY; 3663703f53bSSrinivas Pandruvada } 3673703f53bSSrinivas Pandruvada 3683703f53bSSrinivas Pandruvada if (ishtp_hbm_cl_connect_req(dev, cl)) { 3693703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() HBM connect req fail\n", __func__); 3703703f53bSSrinivas Pandruvada return -ENODEV; 3713703f53bSSrinivas Pandruvada } 3723703f53bSSrinivas Pandruvada 3733703f53bSSrinivas Pandruvada rets = wait_event_interruptible_timeout(cl->wait_ctrl_res, 3743703f53bSSrinivas Pandruvada (dev->dev_state == ISHTP_DEV_ENABLED && 3753703f53bSSrinivas Pandruvada (cl->state == ISHTP_CL_CONNECTED || 3763703f53bSSrinivas Pandruvada cl->state == ISHTP_CL_DISCONNECTED)), 3773703f53bSSrinivas Pandruvada ishtp_secs_to_jiffies( 3783703f53bSSrinivas Pandruvada ISHTP_CL_CONNECT_TIMEOUT)); 3793703f53bSSrinivas Pandruvada /* 3803703f53bSSrinivas Pandruvada * If FW reset arrived, this will happen. Don't check cl->, 3813703f53bSSrinivas Pandruvada * as 'cl' may be freed already 3823703f53bSSrinivas Pandruvada */ 3833703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) { 3843703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n", 3853703f53bSSrinivas Pandruvada __func__); 3863703f53bSSrinivas Pandruvada return -EFAULT; 3873703f53bSSrinivas Pandruvada } 3883703f53bSSrinivas Pandruvada 3893703f53bSSrinivas Pandruvada if (cl->state != ISHTP_CL_CONNECTED) { 3903703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() state != ISHTP_CL_CONNECTED\n", 3913703f53bSSrinivas Pandruvada __func__); 3923703f53bSSrinivas Pandruvada return -EFAULT; 3933703f53bSSrinivas Pandruvada } 3943703f53bSSrinivas Pandruvada 3953703f53bSSrinivas Pandruvada rets = cl->status; 3963703f53bSSrinivas Pandruvada if (rets) { 3973703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Invalid status\n", __func__); 3983703f53bSSrinivas Pandruvada return rets; 3993703f53bSSrinivas Pandruvada } 4003703f53bSSrinivas Pandruvada 4013703f53bSSrinivas Pandruvada rets = ishtp_cl_device_bind(cl); 4023703f53bSSrinivas Pandruvada if (rets) { 4033703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Bind error\n", __func__); 4043703f53bSSrinivas Pandruvada ishtp_cl_disconnect(cl); 4053703f53bSSrinivas Pandruvada return rets; 4063703f53bSSrinivas Pandruvada } 4073703f53bSSrinivas Pandruvada 4083703f53bSSrinivas Pandruvada rets = ishtp_cl_alloc_rx_ring(cl); 4093703f53bSSrinivas Pandruvada if (rets) { 4103703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__); 4113703f53bSSrinivas Pandruvada /* if failed allocation, disconnect */ 4123703f53bSSrinivas Pandruvada ishtp_cl_disconnect(cl); 4133703f53bSSrinivas Pandruvada return rets; 4143703f53bSSrinivas Pandruvada } 4153703f53bSSrinivas Pandruvada 4163703f53bSSrinivas Pandruvada rets = ishtp_cl_alloc_tx_ring(cl); 4173703f53bSSrinivas Pandruvada if (rets) { 4183703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() Alloc TX ring failed\n", __func__); 4193703f53bSSrinivas Pandruvada /* if failed allocation, disconnect */ 4203703f53bSSrinivas Pandruvada ishtp_cl_free_rx_ring(cl); 4213703f53bSSrinivas Pandruvada ishtp_cl_disconnect(cl); 4223703f53bSSrinivas Pandruvada return rets; 4233703f53bSSrinivas Pandruvada } 4243703f53bSSrinivas Pandruvada 4253703f53bSSrinivas Pandruvada /* Upon successful connection and allocation, emit flow-control */ 4263703f53bSSrinivas Pandruvada rets = ishtp_cl_read_start(cl); 4273703f53bSSrinivas Pandruvada 4283703f53bSSrinivas Pandruvada dev->print_log(dev, "%s() successful\n", __func__); 4293703f53bSSrinivas Pandruvada 4303703f53bSSrinivas Pandruvada return rets; 4313703f53bSSrinivas Pandruvada } 4323703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_connect); 4333703f53bSSrinivas Pandruvada 4343703f53bSSrinivas Pandruvada /** 4353703f53bSSrinivas Pandruvada * ishtp_cl_read_start() - Prepare to read client message 4363703f53bSSrinivas Pandruvada * @cl: client device instance 4373703f53bSSrinivas Pandruvada * 4383703f53bSSrinivas Pandruvada * Get a free buffer from pool of free read buffers and add to read buffer 4393703f53bSSrinivas Pandruvada * pool to add contents. Send a flow control request to firmware to be able 4403703f53bSSrinivas Pandruvada * send next message. 4413703f53bSSrinivas Pandruvada * 4423703f53bSSrinivas Pandruvada * Return: 0 if successful or error code on failure 4433703f53bSSrinivas Pandruvada */ 4443703f53bSSrinivas Pandruvada int ishtp_cl_read_start(struct ishtp_cl *cl) 4453703f53bSSrinivas Pandruvada { 4463703f53bSSrinivas Pandruvada struct ishtp_device *dev; 4473703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb; 4483703f53bSSrinivas Pandruvada int rets; 4493703f53bSSrinivas Pandruvada int i; 4503703f53bSSrinivas Pandruvada unsigned long flags; 4513703f53bSSrinivas Pandruvada unsigned long dev_flags; 4523703f53bSSrinivas Pandruvada 4533703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 4543703f53bSSrinivas Pandruvada return -ENODEV; 4553703f53bSSrinivas Pandruvada 4563703f53bSSrinivas Pandruvada dev = cl->dev; 4573703f53bSSrinivas Pandruvada 4583703f53bSSrinivas Pandruvada if (cl->state != ISHTP_CL_CONNECTED) 4593703f53bSSrinivas Pandruvada return -ENODEV; 4603703f53bSSrinivas Pandruvada 4613703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) 4623703f53bSSrinivas Pandruvada return -ENODEV; 4633703f53bSSrinivas Pandruvada 4643703f53bSSrinivas Pandruvada i = ishtp_fw_cl_by_id(dev, cl->fw_client_id); 4653703f53bSSrinivas Pandruvada if (i < 0) { 4663703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, "no such fw client %d\n", 4673703f53bSSrinivas Pandruvada cl->fw_client_id); 4683703f53bSSrinivas Pandruvada return -ENODEV; 4693703f53bSSrinivas Pandruvada } 4703703f53bSSrinivas Pandruvada 4713703f53bSSrinivas Pandruvada /* The current rb is the head of the free rb list */ 4723703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->free_list_spinlock, flags); 4733703f53bSSrinivas Pandruvada if (list_empty(&cl->free_rb_list.list)) { 4743703f53bSSrinivas Pandruvada dev_warn(&cl->device->dev, 4753703f53bSSrinivas Pandruvada "[ishtp-ish] Rx buffers pool is empty\n"); 4763703f53bSSrinivas Pandruvada rets = -ENOMEM; 4773703f53bSSrinivas Pandruvada rb = NULL; 4783703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 4793703f53bSSrinivas Pandruvada goto out; 4803703f53bSSrinivas Pandruvada } 4813703f53bSSrinivas Pandruvada rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb, list); 4823703f53bSSrinivas Pandruvada list_del_init(&rb->list); 4833703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 4843703f53bSSrinivas Pandruvada 4853703f53bSSrinivas Pandruvada rb->cl = cl; 4863703f53bSSrinivas Pandruvada rb->buf_idx = 0; 4873703f53bSSrinivas Pandruvada 4883703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&rb->list); 4893703f53bSSrinivas Pandruvada rets = 0; 4903703f53bSSrinivas Pandruvada 4913703f53bSSrinivas Pandruvada /* 4923703f53bSSrinivas Pandruvada * This must be BEFORE sending flow control - 4933703f53bSSrinivas Pandruvada * response in ISR may come too fast... 4943703f53bSSrinivas Pandruvada */ 4953703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->read_list_spinlock, dev_flags); 4963703f53bSSrinivas Pandruvada list_add_tail(&rb->list, &dev->read_list.list); 4973703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags); 4983703f53bSSrinivas Pandruvada if (ishtp_hbm_cl_flow_control_req(dev, cl)) { 4993703f53bSSrinivas Pandruvada rets = -ENODEV; 5003703f53bSSrinivas Pandruvada goto out; 5013703f53bSSrinivas Pandruvada } 5023703f53bSSrinivas Pandruvada out: 5033703f53bSSrinivas Pandruvada /* if ishtp_hbm_cl_flow_control_req failed, return rb to free list */ 5043703f53bSSrinivas Pandruvada if (rets && rb) { 5053703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->read_list_spinlock, dev_flags); 5063703f53bSSrinivas Pandruvada list_del(&rb->list); 5073703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags); 5083703f53bSSrinivas Pandruvada 5093703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->free_list_spinlock, flags); 5103703f53bSSrinivas Pandruvada list_add_tail(&rb->list, &cl->free_rb_list.list); 5113703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags); 5123703f53bSSrinivas Pandruvada } 5133703f53bSSrinivas Pandruvada return rets; 5143703f53bSSrinivas Pandruvada } 5153703f53bSSrinivas Pandruvada 5163703f53bSSrinivas Pandruvada /** 5173703f53bSSrinivas Pandruvada * ishtp_cl_send() - Send a message to firmware 5183703f53bSSrinivas Pandruvada * @cl: client device instance 5193703f53bSSrinivas Pandruvada * @buf: message buffer 5203703f53bSSrinivas Pandruvada * @length: length of message 5213703f53bSSrinivas Pandruvada * 5223703f53bSSrinivas Pandruvada * If the client is correct state to send message, this function gets a buffer 5233703f53bSSrinivas Pandruvada * from tx ring buffers, copy the message data and call to send the message 5243703f53bSSrinivas Pandruvada * using ishtp_cl_send_msg() 5253703f53bSSrinivas Pandruvada * 5263703f53bSSrinivas Pandruvada * Return: 0 if successful or error code on failure 5273703f53bSSrinivas Pandruvada */ 5283703f53bSSrinivas Pandruvada int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length) 5293703f53bSSrinivas Pandruvada { 5303703f53bSSrinivas Pandruvada struct ishtp_device *dev; 5313703f53bSSrinivas Pandruvada int id; 5323703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring *cl_msg; 5333703f53bSSrinivas Pandruvada int have_msg_to_send = 0; 5343703f53bSSrinivas Pandruvada unsigned long tx_flags, tx_free_flags; 5353703f53bSSrinivas Pandruvada 5363703f53bSSrinivas Pandruvada if (WARN_ON(!cl || !cl->dev)) 5373703f53bSSrinivas Pandruvada return -ENODEV; 5383703f53bSSrinivas Pandruvada 5393703f53bSSrinivas Pandruvada dev = cl->dev; 5403703f53bSSrinivas Pandruvada 5413703f53bSSrinivas Pandruvada if (cl->state != ISHTP_CL_CONNECTED) { 5423703f53bSSrinivas Pandruvada ++cl->err_send_msg; 5433703f53bSSrinivas Pandruvada return -EPIPE; 5443703f53bSSrinivas Pandruvada } 5453703f53bSSrinivas Pandruvada 5463703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) { 5473703f53bSSrinivas Pandruvada ++cl->err_send_msg; 5483703f53bSSrinivas Pandruvada return -ENODEV; 5493703f53bSSrinivas Pandruvada } 5503703f53bSSrinivas Pandruvada 5513703f53bSSrinivas Pandruvada /* Check if we have fw client device */ 5523703f53bSSrinivas Pandruvada id = ishtp_fw_cl_by_id(dev, cl->fw_client_id); 5533703f53bSSrinivas Pandruvada if (id < 0) { 5543703f53bSSrinivas Pandruvada ++cl->err_send_msg; 5553703f53bSSrinivas Pandruvada return -ENOENT; 5563703f53bSSrinivas Pandruvada } 5573703f53bSSrinivas Pandruvada 5583703f53bSSrinivas Pandruvada if (length > dev->fw_clients[id].props.max_msg_length) { 5593703f53bSSrinivas Pandruvada ++cl->err_send_msg; 5603703f53bSSrinivas Pandruvada return -EMSGSIZE; 5613703f53bSSrinivas Pandruvada } 5623703f53bSSrinivas Pandruvada 5633703f53bSSrinivas Pandruvada /* No free bufs */ 5643703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 5653703f53bSSrinivas Pandruvada if (list_empty(&cl->tx_free_list.list)) { 5663703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 5673703f53bSSrinivas Pandruvada tx_free_flags); 5683703f53bSSrinivas Pandruvada ++cl->err_send_msg; 5693703f53bSSrinivas Pandruvada return -ENOMEM; 5703703f53bSSrinivas Pandruvada } 5713703f53bSSrinivas Pandruvada 5723703f53bSSrinivas Pandruvada cl_msg = list_first_entry(&cl->tx_free_list.list, 5733703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring, list); 5743703f53bSSrinivas Pandruvada if (!cl_msg->send_buf.data) { 5753703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 5763703f53bSSrinivas Pandruvada tx_free_flags); 5773703f53bSSrinivas Pandruvada return -EIO; 5783703f53bSSrinivas Pandruvada /* Should not happen, as free list is pre-allocated */ 5793703f53bSSrinivas Pandruvada } 5803703f53bSSrinivas Pandruvada /* 5813703f53bSSrinivas Pandruvada * This is safe, as 'length' is already checked for not exceeding 5823703f53bSSrinivas Pandruvada * max ISHTP message size per client 5833703f53bSSrinivas Pandruvada */ 5843703f53bSSrinivas Pandruvada list_del_init(&cl_msg->list); 58518c0b546SSrinivas Pandruvada --cl->tx_ring_free_size; 58618c0b546SSrinivas Pandruvada 5873703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 5883703f53bSSrinivas Pandruvada memcpy(cl_msg->send_buf.data, buf, length); 5893703f53bSSrinivas Pandruvada cl_msg->send_buf.size = length; 5903703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 5913703f53bSSrinivas Pandruvada have_msg_to_send = !list_empty(&cl->tx_list.list); 5923703f53bSSrinivas Pandruvada list_add_tail(&cl_msg->list, &cl->tx_list.list); 5933703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 5943703f53bSSrinivas Pandruvada 5953703f53bSSrinivas Pandruvada if (!have_msg_to_send && cl->ishtp_flow_ctrl_creds > 0) 5963703f53bSSrinivas Pandruvada ishtp_cl_send_msg(dev, cl); 5973703f53bSSrinivas Pandruvada 5983703f53bSSrinivas Pandruvada return 0; 5993703f53bSSrinivas Pandruvada } 6003703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_send); 6013703f53bSSrinivas Pandruvada 6023703f53bSSrinivas Pandruvada /** 6033703f53bSSrinivas Pandruvada * ishtp_cl_read_complete() - read complete 6043703f53bSSrinivas Pandruvada * @rb: Pointer to client request block 6053703f53bSSrinivas Pandruvada * 6063703f53bSSrinivas Pandruvada * If the message is completely received call ishtp_cl_bus_rx_event() 6073703f53bSSrinivas Pandruvada * to process message 6083703f53bSSrinivas Pandruvada */ 6093703f53bSSrinivas Pandruvada static void ishtp_cl_read_complete(struct ishtp_cl_rb *rb) 6103703f53bSSrinivas Pandruvada { 6113703f53bSSrinivas Pandruvada unsigned long flags; 6123703f53bSSrinivas Pandruvada int schedule_work_flag = 0; 6133703f53bSSrinivas Pandruvada struct ishtp_cl *cl = rb->cl; 6143703f53bSSrinivas Pandruvada 6153703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->in_process_spinlock, flags); 6163703f53bSSrinivas Pandruvada /* 6173703f53bSSrinivas Pandruvada * if in-process list is empty, then need to schedule 6183703f53bSSrinivas Pandruvada * the processing thread 6193703f53bSSrinivas Pandruvada */ 6203703f53bSSrinivas Pandruvada schedule_work_flag = list_empty(&cl->in_process_list.list); 6213703f53bSSrinivas Pandruvada list_add_tail(&rb->list, &cl->in_process_list.list); 6223703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->in_process_spinlock, flags); 6233703f53bSSrinivas Pandruvada 6243703f53bSSrinivas Pandruvada if (schedule_work_flag) 6253703f53bSSrinivas Pandruvada ishtp_cl_bus_rx_event(cl->device); 6263703f53bSSrinivas Pandruvada } 6273703f53bSSrinivas Pandruvada 6283703f53bSSrinivas Pandruvada /** 6293703f53bSSrinivas Pandruvada * ipc_tx_callback() - IPC tx callback function 6303703f53bSSrinivas Pandruvada * @prm: Pointer to client device instance 6313703f53bSSrinivas Pandruvada * 6323703f53bSSrinivas Pandruvada * Send message over IPC either first time or on callback on previous message 6333703f53bSSrinivas Pandruvada * completion 6343703f53bSSrinivas Pandruvada */ 6353703f53bSSrinivas Pandruvada static void ipc_tx_callback(void *prm) 6363703f53bSSrinivas Pandruvada { 6373703f53bSSrinivas Pandruvada struct ishtp_cl *cl = prm; 6383703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring *cl_msg; 6393703f53bSSrinivas Pandruvada size_t rem; 6403703f53bSSrinivas Pandruvada struct ishtp_device *dev = (cl ? cl->dev : NULL); 6413703f53bSSrinivas Pandruvada struct ishtp_msg_hdr ishtp_hdr; 6423703f53bSSrinivas Pandruvada unsigned long tx_flags, tx_free_flags; 6433703f53bSSrinivas Pandruvada unsigned char *pmsg; 6443703f53bSSrinivas Pandruvada 6453703f53bSSrinivas Pandruvada if (!dev) 6463703f53bSSrinivas Pandruvada return; 6473703f53bSSrinivas Pandruvada 6483703f53bSSrinivas Pandruvada /* 6493703f53bSSrinivas Pandruvada * Other conditions if some critical error has 6503703f53bSSrinivas Pandruvada * occurred before this callback is called 6513703f53bSSrinivas Pandruvada */ 6523703f53bSSrinivas Pandruvada if (dev->dev_state != ISHTP_DEV_ENABLED) 6533703f53bSSrinivas Pandruvada return; 6543703f53bSSrinivas Pandruvada 6553703f53bSSrinivas Pandruvada if (cl->state != ISHTP_CL_CONNECTED) 6563703f53bSSrinivas Pandruvada return; 6573703f53bSSrinivas Pandruvada 6583703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 6593703f53bSSrinivas Pandruvada if (list_empty(&cl->tx_list.list)) { 6603703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 6613703f53bSSrinivas Pandruvada return; 6623703f53bSSrinivas Pandruvada } 6633703f53bSSrinivas Pandruvada 6643703f53bSSrinivas Pandruvada if (cl->ishtp_flow_ctrl_creds != 1 && !cl->sending) { 6653703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 6663703f53bSSrinivas Pandruvada return; 6673703f53bSSrinivas Pandruvada } 6683703f53bSSrinivas Pandruvada 6693703f53bSSrinivas Pandruvada if (!cl->sending) { 6703703f53bSSrinivas Pandruvada --cl->ishtp_flow_ctrl_creds; 6713703f53bSSrinivas Pandruvada cl->last_ipc_acked = 0; 6723703f53bSSrinivas Pandruvada cl->last_tx_path = CL_TX_PATH_IPC; 6733703f53bSSrinivas Pandruvada cl->sending = 1; 6743703f53bSSrinivas Pandruvada } 6753703f53bSSrinivas Pandruvada 6763703f53bSSrinivas Pandruvada cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring, 6773703f53bSSrinivas Pandruvada list); 6783703f53bSSrinivas Pandruvada rem = cl_msg->send_buf.size - cl->tx_offs; 6793703f53bSSrinivas Pandruvada 6803703f53bSSrinivas Pandruvada ishtp_hdr.host_addr = cl->host_client_id; 6813703f53bSSrinivas Pandruvada ishtp_hdr.fw_addr = cl->fw_client_id; 6823703f53bSSrinivas Pandruvada ishtp_hdr.reserved = 0; 6833703f53bSSrinivas Pandruvada pmsg = cl_msg->send_buf.data + cl->tx_offs; 6843703f53bSSrinivas Pandruvada 6853703f53bSSrinivas Pandruvada if (rem <= dev->mtu) { 6863703f53bSSrinivas Pandruvada ishtp_hdr.length = rem; 6873703f53bSSrinivas Pandruvada ishtp_hdr.msg_complete = 1; 6883703f53bSSrinivas Pandruvada cl->sending = 0; 6893703f53bSSrinivas Pandruvada list_del_init(&cl_msg->list); /* Must be before write */ 6903703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 6913703f53bSSrinivas Pandruvada /* Submit to IPC queue with no callback */ 6923703f53bSSrinivas Pandruvada ishtp_write_message(dev, &ishtp_hdr, pmsg); 6933703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 6943703f53bSSrinivas Pandruvada list_add_tail(&cl_msg->list, &cl->tx_free_list.list); 69518c0b546SSrinivas Pandruvada ++cl->tx_ring_free_size; 6963703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, 6973703f53bSSrinivas Pandruvada tx_free_flags); 6983703f53bSSrinivas Pandruvada } else { 6993703f53bSSrinivas Pandruvada /* Send IPC fragment */ 7003703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 7013703f53bSSrinivas Pandruvada cl->tx_offs += dev->mtu; 7023703f53bSSrinivas Pandruvada ishtp_hdr.length = dev->mtu; 7033703f53bSSrinivas Pandruvada ishtp_hdr.msg_complete = 0; 7043703f53bSSrinivas Pandruvada ishtp_send_msg(dev, &ishtp_hdr, pmsg, ipc_tx_callback, cl); 7053703f53bSSrinivas Pandruvada } 7063703f53bSSrinivas Pandruvada } 7073703f53bSSrinivas Pandruvada 7083703f53bSSrinivas Pandruvada /** 7093703f53bSSrinivas Pandruvada * ishtp_cl_send_msg_ipc() -Send message using IPC 7103703f53bSSrinivas Pandruvada * @dev: ISHTP device instance 7113703f53bSSrinivas Pandruvada * @cl: Pointer to client device instance 7123703f53bSSrinivas Pandruvada * 7133703f53bSSrinivas Pandruvada * Send message over IPC not using DMA 7143703f53bSSrinivas Pandruvada */ 7153703f53bSSrinivas Pandruvada static void ishtp_cl_send_msg_ipc(struct ishtp_device *dev, 7163703f53bSSrinivas Pandruvada struct ishtp_cl *cl) 7173703f53bSSrinivas Pandruvada { 7183703f53bSSrinivas Pandruvada /* If last DMA message wasn't acked yet, leave this one in Tx queue */ 7193703f53bSSrinivas Pandruvada if (cl->last_tx_path == CL_TX_PATH_DMA && cl->last_dma_acked == 0) 7203703f53bSSrinivas Pandruvada return; 7213703f53bSSrinivas Pandruvada 7223703f53bSSrinivas Pandruvada cl->tx_offs = 0; 7233703f53bSSrinivas Pandruvada ipc_tx_callback(cl); 7243703f53bSSrinivas Pandruvada ++cl->send_msg_cnt_ipc; 7253703f53bSSrinivas Pandruvada } 7263703f53bSSrinivas Pandruvada 7273703f53bSSrinivas Pandruvada /** 7283703f53bSSrinivas Pandruvada * ishtp_cl_send_msg_dma() -Send message using DMA 7293703f53bSSrinivas Pandruvada * @dev: ISHTP device instance 7303703f53bSSrinivas Pandruvada * @cl: Pointer to client device instance 7313703f53bSSrinivas Pandruvada * 7323703f53bSSrinivas Pandruvada * Send message using DMA 7333703f53bSSrinivas Pandruvada */ 7343703f53bSSrinivas Pandruvada static void ishtp_cl_send_msg_dma(struct ishtp_device *dev, 7353703f53bSSrinivas Pandruvada struct ishtp_cl *cl) 7363703f53bSSrinivas Pandruvada { 7373703f53bSSrinivas Pandruvada struct ishtp_msg_hdr hdr; 7383703f53bSSrinivas Pandruvada struct dma_xfer_hbm dma_xfer; 7393703f53bSSrinivas Pandruvada unsigned char *msg_addr; 7403703f53bSSrinivas Pandruvada int off; 7413703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring *cl_msg; 7423703f53bSSrinivas Pandruvada unsigned long tx_flags, tx_free_flags; 7433703f53bSSrinivas Pandruvada 7443703f53bSSrinivas Pandruvada /* If last IPC message wasn't acked yet, leave this one in Tx queue */ 7453703f53bSSrinivas Pandruvada if (cl->last_tx_path == CL_TX_PATH_IPC && cl->last_ipc_acked == 0) 7463703f53bSSrinivas Pandruvada return; 7473703f53bSSrinivas Pandruvada 7483703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); 7493703f53bSSrinivas Pandruvada if (list_empty(&cl->tx_list.list)) { 7503703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 7513703f53bSSrinivas Pandruvada return; 7523703f53bSSrinivas Pandruvada } 7533703f53bSSrinivas Pandruvada 7543703f53bSSrinivas Pandruvada cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring, 7553703f53bSSrinivas Pandruvada list); 7563703f53bSSrinivas Pandruvada 7573703f53bSSrinivas Pandruvada msg_addr = ishtp_cl_get_dma_send_buf(dev, cl_msg->send_buf.size); 7583703f53bSSrinivas Pandruvada if (!msg_addr) { 7593703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 7603703f53bSSrinivas Pandruvada if (dev->transfer_path == CL_TX_PATH_DEFAULT) 7613703f53bSSrinivas Pandruvada ishtp_cl_send_msg_ipc(dev, cl); 7623703f53bSSrinivas Pandruvada return; 7633703f53bSSrinivas Pandruvada } 7643703f53bSSrinivas Pandruvada 7653703f53bSSrinivas Pandruvada list_del_init(&cl_msg->list); /* Must be before write */ 7663703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); 7673703f53bSSrinivas Pandruvada 7683703f53bSSrinivas Pandruvada --cl->ishtp_flow_ctrl_creds; 7693703f53bSSrinivas Pandruvada cl->last_dma_acked = 0; 7703703f53bSSrinivas Pandruvada cl->last_dma_addr = msg_addr; 7713703f53bSSrinivas Pandruvada cl->last_tx_path = CL_TX_PATH_DMA; 7723703f53bSSrinivas Pandruvada 7733703f53bSSrinivas Pandruvada /* write msg to dma buf */ 7743703f53bSSrinivas Pandruvada memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size); 7753703f53bSSrinivas Pandruvada 7763703f53bSSrinivas Pandruvada /* send dma_xfer hbm msg */ 7773703f53bSSrinivas Pandruvada off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf; 7783703f53bSSrinivas Pandruvada ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm)); 7793703f53bSSrinivas Pandruvada dma_xfer.hbm = DMA_XFER; 7803703f53bSSrinivas Pandruvada dma_xfer.fw_client_id = cl->fw_client_id; 7813703f53bSSrinivas Pandruvada dma_xfer.host_client_id = cl->host_client_id; 7823703f53bSSrinivas Pandruvada dma_xfer.reserved = 0; 7833703f53bSSrinivas Pandruvada dma_xfer.msg_addr = dev->ishtp_host_dma_tx_buf_phys + off; 7843703f53bSSrinivas Pandruvada dma_xfer.msg_length = cl_msg->send_buf.size; 7853703f53bSSrinivas Pandruvada dma_xfer.reserved2 = 0; 7863703f53bSSrinivas Pandruvada ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer); 7873703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); 7883703f53bSSrinivas Pandruvada list_add_tail(&cl_msg->list, &cl->tx_free_list.list); 78918c0b546SSrinivas Pandruvada ++cl->tx_ring_free_size; 7903703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); 7913703f53bSSrinivas Pandruvada ++cl->send_msg_cnt_dma; 7923703f53bSSrinivas Pandruvada } 7933703f53bSSrinivas Pandruvada 7943703f53bSSrinivas Pandruvada /** 7953703f53bSSrinivas Pandruvada * ishtp_cl_send_msg() -Send message using DMA or IPC 7963703f53bSSrinivas Pandruvada * @dev: ISHTP device instance 7973703f53bSSrinivas Pandruvada * @cl: Pointer to client device instance 7983703f53bSSrinivas Pandruvada * 7993703f53bSSrinivas Pandruvada * Send message using DMA or IPC based on transfer_path 8003703f53bSSrinivas Pandruvada */ 8013703f53bSSrinivas Pandruvada void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl) 8023703f53bSSrinivas Pandruvada { 8033703f53bSSrinivas Pandruvada if (dev->transfer_path == CL_TX_PATH_DMA) 8043703f53bSSrinivas Pandruvada ishtp_cl_send_msg_dma(dev, cl); 8053703f53bSSrinivas Pandruvada else 8063703f53bSSrinivas Pandruvada ishtp_cl_send_msg_ipc(dev, cl); 8073703f53bSSrinivas Pandruvada } 8083703f53bSSrinivas Pandruvada 8093703f53bSSrinivas Pandruvada /** 8103703f53bSSrinivas Pandruvada * recv_ishtp_cl_msg() -Receive client message 8113703f53bSSrinivas Pandruvada * @dev: ISHTP device instance 8123703f53bSSrinivas Pandruvada * @ishtp_hdr: Pointer to message header 8133703f53bSSrinivas Pandruvada * 8143703f53bSSrinivas Pandruvada * Receive and dispatch ISHTP client messages. This function executes in ISR 815538be0aaSArnd Bergmann * or work queue context 8163703f53bSSrinivas Pandruvada */ 8173703f53bSSrinivas Pandruvada void recv_ishtp_cl_msg(struct ishtp_device *dev, 8183703f53bSSrinivas Pandruvada struct ishtp_msg_hdr *ishtp_hdr) 8193703f53bSSrinivas Pandruvada { 8203703f53bSSrinivas Pandruvada struct ishtp_cl *cl; 8213703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb; 8223703f53bSSrinivas Pandruvada struct ishtp_cl_rb *new_rb; 8233703f53bSSrinivas Pandruvada unsigned char *buffer = NULL; 8243703f53bSSrinivas Pandruvada struct ishtp_cl_rb *complete_rb = NULL; 8253703f53bSSrinivas Pandruvada unsigned long flags; 8263703f53bSSrinivas Pandruvada int rb_count; 8273703f53bSSrinivas Pandruvada 8283703f53bSSrinivas Pandruvada if (ishtp_hdr->reserved) { 8293703f53bSSrinivas Pandruvada dev_err(dev->devc, "corrupted message header.\n"); 8303703f53bSSrinivas Pandruvada goto eoi; 8313703f53bSSrinivas Pandruvada } 8323703f53bSSrinivas Pandruvada 8333703f53bSSrinivas Pandruvada if (ishtp_hdr->length > IPC_PAYLOAD_SIZE) { 8343703f53bSSrinivas Pandruvada dev_err(dev->devc, 8353703f53bSSrinivas Pandruvada "ISHTP message length in hdr exceeds IPC MTU\n"); 8363703f53bSSrinivas Pandruvada goto eoi; 8373703f53bSSrinivas Pandruvada } 8383703f53bSSrinivas Pandruvada 839538be0aaSArnd Bergmann spin_lock_irqsave(&dev->read_list_spinlock, flags); 8403703f53bSSrinivas Pandruvada rb_count = -1; 8413703f53bSSrinivas Pandruvada list_for_each_entry(rb, &dev->read_list.list, list) { 8423703f53bSSrinivas Pandruvada ++rb_count; 8433703f53bSSrinivas Pandruvada cl = rb->cl; 8443703f53bSSrinivas Pandruvada if (!cl || !(cl->host_client_id == ishtp_hdr->host_addr && 8453703f53bSSrinivas Pandruvada cl->fw_client_id == ishtp_hdr->fw_addr) || 8463703f53bSSrinivas Pandruvada !(cl->state == ISHTP_CL_CONNECTED)) 8473703f53bSSrinivas Pandruvada continue; 8483703f53bSSrinivas Pandruvada 8493703f53bSSrinivas Pandruvada /* If no Rx buffer is allocated, disband the rb */ 8503703f53bSSrinivas Pandruvada if (rb->buffer.size == 0 || rb->buffer.data == NULL) { 851538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 8523703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, 8533703f53bSSrinivas Pandruvada "Rx buffer is not allocated.\n"); 8543703f53bSSrinivas Pandruvada list_del(&rb->list); 8553703f53bSSrinivas Pandruvada ishtp_io_rb_free(rb); 8563703f53bSSrinivas Pandruvada cl->status = -ENOMEM; 8573703f53bSSrinivas Pandruvada goto eoi; 8583703f53bSSrinivas Pandruvada } 8593703f53bSSrinivas Pandruvada 8603703f53bSSrinivas Pandruvada /* 8613703f53bSSrinivas Pandruvada * If message buffer overflown (exceeds max. client msg 8623703f53bSSrinivas Pandruvada * size, drop message and return to free buffer. 8633703f53bSSrinivas Pandruvada * Do we need to disconnect such a client? (We don't send 8643703f53bSSrinivas Pandruvada * back FC, so communication will be stuck anyway) 8653703f53bSSrinivas Pandruvada */ 8663703f53bSSrinivas Pandruvada if (rb->buffer.size < ishtp_hdr->length + rb->buf_idx) { 867538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 8683703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, 8693703f53bSSrinivas Pandruvada "message overflow. size %d len %d idx %ld\n", 8703703f53bSSrinivas Pandruvada rb->buffer.size, ishtp_hdr->length, 8713703f53bSSrinivas Pandruvada rb->buf_idx); 8723703f53bSSrinivas Pandruvada list_del(&rb->list); 8733703f53bSSrinivas Pandruvada ishtp_cl_io_rb_recycle(rb); 8743703f53bSSrinivas Pandruvada cl->status = -EIO; 8753703f53bSSrinivas Pandruvada goto eoi; 8763703f53bSSrinivas Pandruvada } 8773703f53bSSrinivas Pandruvada 8783703f53bSSrinivas Pandruvada buffer = rb->buffer.data + rb->buf_idx; 8793703f53bSSrinivas Pandruvada dev->ops->ishtp_read(dev, buffer, ishtp_hdr->length); 8803703f53bSSrinivas Pandruvada 8813703f53bSSrinivas Pandruvada rb->buf_idx += ishtp_hdr->length; 8823703f53bSSrinivas Pandruvada if (ishtp_hdr->msg_complete) { 8833703f53bSSrinivas Pandruvada /* Last fragment in message - it's complete */ 8843703f53bSSrinivas Pandruvada cl->status = 0; 8853703f53bSSrinivas Pandruvada list_del(&rb->list); 8863703f53bSSrinivas Pandruvada complete_rb = rb; 8873703f53bSSrinivas Pandruvada 8883703f53bSSrinivas Pandruvada --cl->out_flow_ctrl_creds; 8893703f53bSSrinivas Pandruvada /* 8903703f53bSSrinivas Pandruvada * the whole msg arrived, send a new FC, and add a new 8913703f53bSSrinivas Pandruvada * rb buffer for the next coming msg 8923703f53bSSrinivas Pandruvada */ 893538be0aaSArnd Bergmann spin_lock(&cl->free_list_spinlock); 8943703f53bSSrinivas Pandruvada 8953703f53bSSrinivas Pandruvada if (!list_empty(&cl->free_rb_list.list)) { 8963703f53bSSrinivas Pandruvada new_rb = list_entry(cl->free_rb_list.list.next, 8973703f53bSSrinivas Pandruvada struct ishtp_cl_rb, list); 8983703f53bSSrinivas Pandruvada list_del_init(&new_rb->list); 899538be0aaSArnd Bergmann spin_unlock(&cl->free_list_spinlock); 9003703f53bSSrinivas Pandruvada new_rb->cl = cl; 9013703f53bSSrinivas Pandruvada new_rb->buf_idx = 0; 9023703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&new_rb->list); 9033703f53bSSrinivas Pandruvada list_add_tail(&new_rb->list, 9043703f53bSSrinivas Pandruvada &dev->read_list.list); 9053703f53bSSrinivas Pandruvada 9063703f53bSSrinivas Pandruvada ishtp_hbm_cl_flow_control_req(dev, cl); 9073703f53bSSrinivas Pandruvada } else { 908538be0aaSArnd Bergmann spin_unlock(&cl->free_list_spinlock); 9093703f53bSSrinivas Pandruvada } 9103703f53bSSrinivas Pandruvada } 9113703f53bSSrinivas Pandruvada /* One more fragment in message (even if this was last) */ 9123703f53bSSrinivas Pandruvada ++cl->recv_msg_num_frags; 9133703f53bSSrinivas Pandruvada 9143703f53bSSrinivas Pandruvada /* 9153703f53bSSrinivas Pandruvada * We can safely break here (and in BH too), 9163703f53bSSrinivas Pandruvada * a single input message can go only to a single request! 9173703f53bSSrinivas Pandruvada */ 9183703f53bSSrinivas Pandruvada break; 9193703f53bSSrinivas Pandruvada } 9203703f53bSSrinivas Pandruvada 921538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 9223703f53bSSrinivas Pandruvada /* If it's nobody's message, just read and discard it */ 9233703f53bSSrinivas Pandruvada if (!buffer) { 9243703f53bSSrinivas Pandruvada uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE]; 9253703f53bSSrinivas Pandruvada 9263703f53bSSrinivas Pandruvada dev_err(dev->devc, "Dropped Rx msg - no request\n"); 9273703f53bSSrinivas Pandruvada dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length); 9283703f53bSSrinivas Pandruvada goto eoi; 9293703f53bSSrinivas Pandruvada } 9303703f53bSSrinivas Pandruvada 9313703f53bSSrinivas Pandruvada if (complete_rb) { 9321260662fSArnd Bergmann cl = complete_rb->cl; 9332503f7baSArnd Bergmann cl->ts_rx = ktime_get(); 9343703f53bSSrinivas Pandruvada ++cl->recv_msg_cnt_ipc; 9353703f53bSSrinivas Pandruvada ishtp_cl_read_complete(complete_rb); 9363703f53bSSrinivas Pandruvada } 9373703f53bSSrinivas Pandruvada eoi: 9383703f53bSSrinivas Pandruvada return; 9393703f53bSSrinivas Pandruvada } 9403703f53bSSrinivas Pandruvada 9413703f53bSSrinivas Pandruvada /** 9423703f53bSSrinivas Pandruvada * recv_ishtp_cl_msg_dma() -Receive client message 9433703f53bSSrinivas Pandruvada * @dev: ISHTP device instance 9443703f53bSSrinivas Pandruvada * @msg: message pointer 9453703f53bSSrinivas Pandruvada * @hbm: hbm buffer 9463703f53bSSrinivas Pandruvada * 9473703f53bSSrinivas Pandruvada * Receive and dispatch ISHTP client messages using DMA. This function executes 948538be0aaSArnd Bergmann * in ISR or work queue context 9493703f53bSSrinivas Pandruvada */ 9503703f53bSSrinivas Pandruvada void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg, 9513703f53bSSrinivas Pandruvada struct dma_xfer_hbm *hbm) 9523703f53bSSrinivas Pandruvada { 9533703f53bSSrinivas Pandruvada struct ishtp_cl *cl; 9543703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb; 9553703f53bSSrinivas Pandruvada struct ishtp_cl_rb *new_rb; 9563703f53bSSrinivas Pandruvada unsigned char *buffer = NULL; 9573703f53bSSrinivas Pandruvada struct ishtp_cl_rb *complete_rb = NULL; 9583703f53bSSrinivas Pandruvada unsigned long flags; 9593703f53bSSrinivas Pandruvada 960538be0aaSArnd Bergmann spin_lock_irqsave(&dev->read_list_spinlock, flags); 961538be0aaSArnd Bergmann 9623703f53bSSrinivas Pandruvada list_for_each_entry(rb, &dev->read_list.list, list) { 9633703f53bSSrinivas Pandruvada cl = rb->cl; 9643703f53bSSrinivas Pandruvada if (!cl || !(cl->host_client_id == hbm->host_client_id && 9653703f53bSSrinivas Pandruvada cl->fw_client_id == hbm->fw_client_id) || 9663703f53bSSrinivas Pandruvada !(cl->state == ISHTP_CL_CONNECTED)) 9673703f53bSSrinivas Pandruvada continue; 9683703f53bSSrinivas Pandruvada 9693703f53bSSrinivas Pandruvada /* 9703703f53bSSrinivas Pandruvada * If no Rx buffer is allocated, disband the rb 9713703f53bSSrinivas Pandruvada */ 9723703f53bSSrinivas Pandruvada if (rb->buffer.size == 0 || rb->buffer.data == NULL) { 973538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 9743703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, 9753703f53bSSrinivas Pandruvada "response buffer is not allocated.\n"); 9763703f53bSSrinivas Pandruvada list_del(&rb->list); 9773703f53bSSrinivas Pandruvada ishtp_io_rb_free(rb); 9783703f53bSSrinivas Pandruvada cl->status = -ENOMEM; 9793703f53bSSrinivas Pandruvada goto eoi; 9803703f53bSSrinivas Pandruvada } 9813703f53bSSrinivas Pandruvada 9823703f53bSSrinivas Pandruvada /* 9833703f53bSSrinivas Pandruvada * If message buffer overflown (exceeds max. client msg 9843703f53bSSrinivas Pandruvada * size, drop message and return to free buffer. 9853703f53bSSrinivas Pandruvada * Do we need to disconnect such a client? (We don't send 9863703f53bSSrinivas Pandruvada * back FC, so communication will be stuck anyway) 9873703f53bSSrinivas Pandruvada */ 9883703f53bSSrinivas Pandruvada if (rb->buffer.size < hbm->msg_length) { 989538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 9903703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, 9913703f53bSSrinivas Pandruvada "message overflow. size %d len %d idx %ld\n", 9923703f53bSSrinivas Pandruvada rb->buffer.size, hbm->msg_length, rb->buf_idx); 9933703f53bSSrinivas Pandruvada list_del(&rb->list); 9943703f53bSSrinivas Pandruvada ishtp_cl_io_rb_recycle(rb); 9953703f53bSSrinivas Pandruvada cl->status = -EIO; 9963703f53bSSrinivas Pandruvada goto eoi; 9973703f53bSSrinivas Pandruvada } 9983703f53bSSrinivas Pandruvada 9993703f53bSSrinivas Pandruvada buffer = rb->buffer.data; 10003703f53bSSrinivas Pandruvada memcpy(buffer, msg, hbm->msg_length); 10013703f53bSSrinivas Pandruvada rb->buf_idx = hbm->msg_length; 10023703f53bSSrinivas Pandruvada 10033703f53bSSrinivas Pandruvada /* Last fragment in message - it's complete */ 10043703f53bSSrinivas Pandruvada cl->status = 0; 10053703f53bSSrinivas Pandruvada list_del(&rb->list); 10063703f53bSSrinivas Pandruvada complete_rb = rb; 10073703f53bSSrinivas Pandruvada 10083703f53bSSrinivas Pandruvada --cl->out_flow_ctrl_creds; 10093703f53bSSrinivas Pandruvada /* 10103703f53bSSrinivas Pandruvada * the whole msg arrived, send a new FC, and add a new 10113703f53bSSrinivas Pandruvada * rb buffer for the next coming msg 10123703f53bSSrinivas Pandruvada */ 1013538be0aaSArnd Bergmann spin_lock(&cl->free_list_spinlock); 10143703f53bSSrinivas Pandruvada 10153703f53bSSrinivas Pandruvada if (!list_empty(&cl->free_rb_list.list)) { 10163703f53bSSrinivas Pandruvada new_rb = list_entry(cl->free_rb_list.list.next, 10173703f53bSSrinivas Pandruvada struct ishtp_cl_rb, list); 10183703f53bSSrinivas Pandruvada list_del_init(&new_rb->list); 1019538be0aaSArnd Bergmann spin_unlock(&cl->free_list_spinlock); 10203703f53bSSrinivas Pandruvada new_rb->cl = cl; 10213703f53bSSrinivas Pandruvada new_rb->buf_idx = 0; 10223703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&new_rb->list); 10233703f53bSSrinivas Pandruvada list_add_tail(&new_rb->list, 10243703f53bSSrinivas Pandruvada &dev->read_list.list); 10253703f53bSSrinivas Pandruvada 10263703f53bSSrinivas Pandruvada ishtp_hbm_cl_flow_control_req(dev, cl); 10273703f53bSSrinivas Pandruvada } else { 1028538be0aaSArnd Bergmann spin_unlock(&cl->free_list_spinlock); 10293703f53bSSrinivas Pandruvada } 10303703f53bSSrinivas Pandruvada 10313703f53bSSrinivas Pandruvada /* One more fragment in message (this is always last) */ 10323703f53bSSrinivas Pandruvada ++cl->recv_msg_num_frags; 10333703f53bSSrinivas Pandruvada 10343703f53bSSrinivas Pandruvada /* 10353703f53bSSrinivas Pandruvada * We can safely break here (and in BH too), 10363703f53bSSrinivas Pandruvada * a single input message can go only to a single request! 10373703f53bSSrinivas Pandruvada */ 10383703f53bSSrinivas Pandruvada break; 10393703f53bSSrinivas Pandruvada } 10403703f53bSSrinivas Pandruvada 1041538be0aaSArnd Bergmann spin_unlock_irqrestore(&dev->read_list_spinlock, flags); 10423703f53bSSrinivas Pandruvada /* If it's nobody's message, just read and discard it */ 10433703f53bSSrinivas Pandruvada if (!buffer) { 10443703f53bSSrinivas Pandruvada dev_err(dev->devc, "Dropped Rx (DMA) msg - no request\n"); 10453703f53bSSrinivas Pandruvada goto eoi; 10463703f53bSSrinivas Pandruvada } 10473703f53bSSrinivas Pandruvada 10483703f53bSSrinivas Pandruvada if (complete_rb) { 10491260662fSArnd Bergmann cl = complete_rb->cl; 10502503f7baSArnd Bergmann cl->ts_rx = ktime_get(); 10513703f53bSSrinivas Pandruvada ++cl->recv_msg_cnt_dma; 10523703f53bSSrinivas Pandruvada ishtp_cl_read_complete(complete_rb); 10533703f53bSSrinivas Pandruvada } 10543703f53bSSrinivas Pandruvada eoi: 10553703f53bSSrinivas Pandruvada return; 10563703f53bSSrinivas Pandruvada } 105751cbc707SSrinivas Pandruvada 105851cbc707SSrinivas Pandruvada void *ishtp_get_client_data(struct ishtp_cl *cl) 105951cbc707SSrinivas Pandruvada { 106051cbc707SSrinivas Pandruvada return cl->client_data; 106151cbc707SSrinivas Pandruvada } 106251cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_client_data); 106351cbc707SSrinivas Pandruvada 106451cbc707SSrinivas Pandruvada void ishtp_set_client_data(struct ishtp_cl *cl, void *data) 106551cbc707SSrinivas Pandruvada { 106651cbc707SSrinivas Pandruvada cl->client_data = data; 106751cbc707SSrinivas Pandruvada } 106851cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_set_client_data); 106951cbc707SSrinivas Pandruvada 107051cbc707SSrinivas Pandruvada struct ishtp_device *ishtp_get_ishtp_device(struct ishtp_cl *cl) 107151cbc707SSrinivas Pandruvada { 107251cbc707SSrinivas Pandruvada return cl->dev; 107351cbc707SSrinivas Pandruvada } 107451cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_ishtp_device); 107551cbc707SSrinivas Pandruvada 107651cbc707SSrinivas Pandruvada void ishtp_set_tx_ring_size(struct ishtp_cl *cl, int size) 107751cbc707SSrinivas Pandruvada { 107851cbc707SSrinivas Pandruvada cl->tx_ring_size = size; 107951cbc707SSrinivas Pandruvada } 108051cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_set_tx_ring_size); 108151cbc707SSrinivas Pandruvada 108251cbc707SSrinivas Pandruvada void ishtp_set_rx_ring_size(struct ishtp_cl *cl, int size) 108351cbc707SSrinivas Pandruvada { 108451cbc707SSrinivas Pandruvada cl->rx_ring_size = size; 108551cbc707SSrinivas Pandruvada } 108651cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_set_rx_ring_size); 108751cbc707SSrinivas Pandruvada 108851cbc707SSrinivas Pandruvada void ishtp_set_connection_state(struct ishtp_cl *cl, int state) 108951cbc707SSrinivas Pandruvada { 109051cbc707SSrinivas Pandruvada cl->state = state; 109151cbc707SSrinivas Pandruvada } 109251cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_set_connection_state); 109351cbc707SSrinivas Pandruvada 109451cbc707SSrinivas Pandruvada void ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id) 109551cbc707SSrinivas Pandruvada { 109651cbc707SSrinivas Pandruvada cl->fw_client_id = fw_client_id; 109751cbc707SSrinivas Pandruvada } 109851cbc707SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_set_fw_client_id); 1099