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