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