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