12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23703f53bSSrinivas Pandruvada /*
33703f53bSSrinivas Pandruvada * ISHTP Ring Buffers
43703f53bSSrinivas Pandruvada *
53703f53bSSrinivas Pandruvada * Copyright (c) 2003-2016, Intel Corporation.
63703f53bSSrinivas Pandruvada */
73703f53bSSrinivas Pandruvada
83703f53bSSrinivas Pandruvada #include <linux/slab.h>
93703f53bSSrinivas Pandruvada #include "client.h"
103703f53bSSrinivas Pandruvada
113703f53bSSrinivas Pandruvada /**
123703f53bSSrinivas Pandruvada * ishtp_cl_alloc_rx_ring() - Allocate RX ring buffers
133703f53bSSrinivas Pandruvada * @cl: client device instance
143703f53bSSrinivas Pandruvada *
153703f53bSSrinivas Pandruvada * Allocate and initialize RX ring buffers
163703f53bSSrinivas Pandruvada *
173703f53bSSrinivas Pandruvada * Return: 0 on success else -ENOMEM
183703f53bSSrinivas Pandruvada */
ishtp_cl_alloc_rx_ring(struct ishtp_cl * cl)193703f53bSSrinivas Pandruvada int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl)
203703f53bSSrinivas Pandruvada {
213703f53bSSrinivas Pandruvada size_t len = cl->device->fw_client->props.max_msg_length;
223703f53bSSrinivas Pandruvada int j;
233703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb;
243703f53bSSrinivas Pandruvada int ret = 0;
253703f53bSSrinivas Pandruvada unsigned long flags;
263703f53bSSrinivas Pandruvada
273703f53bSSrinivas Pandruvada for (j = 0; j < cl->rx_ring_size; ++j) {
283703f53bSSrinivas Pandruvada rb = ishtp_io_rb_init(cl);
293703f53bSSrinivas Pandruvada if (!rb) {
303703f53bSSrinivas Pandruvada ret = -ENOMEM;
313703f53bSSrinivas Pandruvada goto out;
323703f53bSSrinivas Pandruvada }
333703f53bSSrinivas Pandruvada ret = ishtp_io_rb_alloc_buf(rb, len);
343703f53bSSrinivas Pandruvada if (ret)
353703f53bSSrinivas Pandruvada goto out;
363703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->free_list_spinlock, flags);
373703f53bSSrinivas Pandruvada list_add_tail(&rb->list, &cl->free_rb_list.list);
383703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
393703f53bSSrinivas Pandruvada }
403703f53bSSrinivas Pandruvada
413703f53bSSrinivas Pandruvada return 0;
423703f53bSSrinivas Pandruvada
433703f53bSSrinivas Pandruvada out:
443703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, "error in allocating Rx buffers\n");
453703f53bSSrinivas Pandruvada ishtp_cl_free_rx_ring(cl);
463703f53bSSrinivas Pandruvada return ret;
473703f53bSSrinivas Pandruvada }
483703f53bSSrinivas Pandruvada
493703f53bSSrinivas Pandruvada /**
503703f53bSSrinivas Pandruvada * ishtp_cl_alloc_tx_ring() - Allocate TX ring buffers
513703f53bSSrinivas Pandruvada * @cl: client device instance
523703f53bSSrinivas Pandruvada *
533703f53bSSrinivas Pandruvada * Allocate and initialize TX ring buffers
543703f53bSSrinivas Pandruvada *
553703f53bSSrinivas Pandruvada * Return: 0 on success else -ENOMEM
563703f53bSSrinivas Pandruvada */
ishtp_cl_alloc_tx_ring(struct ishtp_cl * cl)573703f53bSSrinivas Pandruvada int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
583703f53bSSrinivas Pandruvada {
593703f53bSSrinivas Pandruvada size_t len = cl->device->fw_client->props.max_msg_length;
603703f53bSSrinivas Pandruvada int j;
613703f53bSSrinivas Pandruvada unsigned long flags;
623703f53bSSrinivas Pandruvada
6318c0b546SSrinivas Pandruvada cl->tx_ring_free_size = 0;
6418c0b546SSrinivas Pandruvada
653703f53bSSrinivas Pandruvada /* Allocate pool to free Tx bufs */
663703f53bSSrinivas Pandruvada for (j = 0; j < cl->tx_ring_size; ++j) {
673703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring *tx_buf;
683703f53bSSrinivas Pandruvada
696cf5c1c7SWei Yongjun tx_buf = kzalloc(sizeof(struct ishtp_cl_tx_ring), GFP_KERNEL);
703703f53bSSrinivas Pandruvada if (!tx_buf)
713703f53bSSrinivas Pandruvada goto out;
723703f53bSSrinivas Pandruvada
733703f53bSSrinivas Pandruvada tx_buf->send_buf.data = kmalloc(len, GFP_KERNEL);
743703f53bSSrinivas Pandruvada if (!tx_buf->send_buf.data) {
753703f53bSSrinivas Pandruvada kfree(tx_buf);
763703f53bSSrinivas Pandruvada goto out;
773703f53bSSrinivas Pandruvada }
783703f53bSSrinivas Pandruvada
793703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
803703f53bSSrinivas Pandruvada list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
8118c0b546SSrinivas Pandruvada ++cl->tx_ring_free_size;
823703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
833703f53bSSrinivas Pandruvada }
843703f53bSSrinivas Pandruvada return 0;
853703f53bSSrinivas Pandruvada out:
863703f53bSSrinivas Pandruvada dev_err(&cl->device->dev, "error in allocating Tx pool\n");
8716ff7bf6SZhang Lixu ishtp_cl_free_tx_ring(cl);
883703f53bSSrinivas Pandruvada return -ENOMEM;
893703f53bSSrinivas Pandruvada }
903703f53bSSrinivas Pandruvada
913703f53bSSrinivas Pandruvada /**
923703f53bSSrinivas Pandruvada * ishtp_cl_free_rx_ring() - Free RX ring buffers
933703f53bSSrinivas Pandruvada * @cl: client device instance
943703f53bSSrinivas Pandruvada *
953703f53bSSrinivas Pandruvada * Free RX ring buffers
963703f53bSSrinivas Pandruvada */
ishtp_cl_free_rx_ring(struct ishtp_cl * cl)973703f53bSSrinivas Pandruvada void ishtp_cl_free_rx_ring(struct ishtp_cl *cl)
983703f53bSSrinivas Pandruvada {
993703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb;
1003703f53bSSrinivas Pandruvada unsigned long flags;
1013703f53bSSrinivas Pandruvada
1023703f53bSSrinivas Pandruvada /* release allocated memory - pass over free_rb_list */
1033703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->free_list_spinlock, flags);
1043703f53bSSrinivas Pandruvada while (!list_empty(&cl->free_rb_list.list)) {
1053703f53bSSrinivas Pandruvada rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb,
1063703f53bSSrinivas Pandruvada list);
1073703f53bSSrinivas Pandruvada list_del(&rb->list);
1083703f53bSSrinivas Pandruvada kfree(rb->buffer.data);
1093703f53bSSrinivas Pandruvada kfree(rb);
1103703f53bSSrinivas Pandruvada }
1113703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
1123703f53bSSrinivas Pandruvada /* release allocated memory - pass over in_process_list */
1133703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->in_process_spinlock, flags);
1143703f53bSSrinivas Pandruvada while (!list_empty(&cl->in_process_list.list)) {
1153703f53bSSrinivas Pandruvada rb = list_entry(cl->in_process_list.list.next,
1163703f53bSSrinivas Pandruvada struct ishtp_cl_rb, list);
1173703f53bSSrinivas Pandruvada list_del(&rb->list);
1183703f53bSSrinivas Pandruvada kfree(rb->buffer.data);
1193703f53bSSrinivas Pandruvada kfree(rb);
1203703f53bSSrinivas Pandruvada }
1213703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->in_process_spinlock, flags);
1223703f53bSSrinivas Pandruvada }
1233703f53bSSrinivas Pandruvada
1243703f53bSSrinivas Pandruvada /**
1253703f53bSSrinivas Pandruvada * ishtp_cl_free_tx_ring() - Free TX ring buffers
1263703f53bSSrinivas Pandruvada * @cl: client device instance
1273703f53bSSrinivas Pandruvada *
1283703f53bSSrinivas Pandruvada * Free TX ring buffers
1293703f53bSSrinivas Pandruvada */
ishtp_cl_free_tx_ring(struct ishtp_cl * cl)1303703f53bSSrinivas Pandruvada void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
1313703f53bSSrinivas Pandruvada {
1323703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring *tx_buf;
1333703f53bSSrinivas Pandruvada unsigned long flags;
1343703f53bSSrinivas Pandruvada
1353703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
1363703f53bSSrinivas Pandruvada /* release allocated memory - pass over tx_free_list */
1373703f53bSSrinivas Pandruvada while (!list_empty(&cl->tx_free_list.list)) {
1383703f53bSSrinivas Pandruvada tx_buf = list_entry(cl->tx_free_list.list.next,
1393703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring, list);
1403703f53bSSrinivas Pandruvada list_del(&tx_buf->list);
14118c0b546SSrinivas Pandruvada --cl->tx_ring_free_size;
1423703f53bSSrinivas Pandruvada kfree(tx_buf->send_buf.data);
1433703f53bSSrinivas Pandruvada kfree(tx_buf);
1443703f53bSSrinivas Pandruvada }
1453703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
1463703f53bSSrinivas Pandruvada
1473703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->tx_list_spinlock, flags);
1483703f53bSSrinivas Pandruvada /* release allocated memory - pass over tx_list */
1493703f53bSSrinivas Pandruvada while (!list_empty(&cl->tx_list.list)) {
1503703f53bSSrinivas Pandruvada tx_buf = list_entry(cl->tx_list.list.next,
1513703f53bSSrinivas Pandruvada struct ishtp_cl_tx_ring, list);
1523703f53bSSrinivas Pandruvada list_del(&tx_buf->list);
1533703f53bSSrinivas Pandruvada kfree(tx_buf->send_buf.data);
1543703f53bSSrinivas Pandruvada kfree(tx_buf);
1553703f53bSSrinivas Pandruvada }
1563703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->tx_list_spinlock, flags);
1573703f53bSSrinivas Pandruvada }
1583703f53bSSrinivas Pandruvada
1593703f53bSSrinivas Pandruvada /**
1603703f53bSSrinivas Pandruvada * ishtp_io_rb_free() - Free IO request block
1613703f53bSSrinivas Pandruvada * @rb: IO request block
1623703f53bSSrinivas Pandruvada *
1633703f53bSSrinivas Pandruvada * Free io request block memory
1643703f53bSSrinivas Pandruvada */
ishtp_io_rb_free(struct ishtp_cl_rb * rb)1653703f53bSSrinivas Pandruvada void ishtp_io_rb_free(struct ishtp_cl_rb *rb)
1663703f53bSSrinivas Pandruvada {
1673703f53bSSrinivas Pandruvada if (rb == NULL)
1683703f53bSSrinivas Pandruvada return;
1693703f53bSSrinivas Pandruvada
1703703f53bSSrinivas Pandruvada kfree(rb->buffer.data);
1713703f53bSSrinivas Pandruvada kfree(rb);
1723703f53bSSrinivas Pandruvada }
1733703f53bSSrinivas Pandruvada
1743703f53bSSrinivas Pandruvada /**
1753703f53bSSrinivas Pandruvada * ishtp_io_rb_init() - Allocate and init IO request block
1763703f53bSSrinivas Pandruvada * @cl: client device instance
1773703f53bSSrinivas Pandruvada *
1783703f53bSSrinivas Pandruvada * Allocate and initialize request block
1793703f53bSSrinivas Pandruvada *
1803703f53bSSrinivas Pandruvada * Return: Allocted IO request block pointer
1813703f53bSSrinivas Pandruvada */
ishtp_io_rb_init(struct ishtp_cl * cl)1823703f53bSSrinivas Pandruvada struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl)
1833703f53bSSrinivas Pandruvada {
1843703f53bSSrinivas Pandruvada struct ishtp_cl_rb *rb;
1853703f53bSSrinivas Pandruvada
1863703f53bSSrinivas Pandruvada rb = kzalloc(sizeof(struct ishtp_cl_rb), GFP_KERNEL);
1873703f53bSSrinivas Pandruvada if (!rb)
1883703f53bSSrinivas Pandruvada return NULL;
1893703f53bSSrinivas Pandruvada
1903703f53bSSrinivas Pandruvada INIT_LIST_HEAD(&rb->list);
1913703f53bSSrinivas Pandruvada rb->cl = cl;
1923703f53bSSrinivas Pandruvada rb->buf_idx = 0;
1933703f53bSSrinivas Pandruvada return rb;
1943703f53bSSrinivas Pandruvada }
1953703f53bSSrinivas Pandruvada
1963703f53bSSrinivas Pandruvada /**
1973703f53bSSrinivas Pandruvada * ishtp_io_rb_alloc_buf() - Allocate and init response buffer
1983703f53bSSrinivas Pandruvada * @rb: IO request block
1993703f53bSSrinivas Pandruvada * @length: length of response buffer
2003703f53bSSrinivas Pandruvada *
2013703f53bSSrinivas Pandruvada * Allocate respose buffer
2023703f53bSSrinivas Pandruvada *
2033703f53bSSrinivas Pandruvada * Return: 0 on success else -ENOMEM
2043703f53bSSrinivas Pandruvada */
ishtp_io_rb_alloc_buf(struct ishtp_cl_rb * rb,size_t length)2053703f53bSSrinivas Pandruvada int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length)
2063703f53bSSrinivas Pandruvada {
2073703f53bSSrinivas Pandruvada if (!rb)
2083703f53bSSrinivas Pandruvada return -EINVAL;
2093703f53bSSrinivas Pandruvada
2103703f53bSSrinivas Pandruvada if (length == 0)
2113703f53bSSrinivas Pandruvada return 0;
2123703f53bSSrinivas Pandruvada
2133703f53bSSrinivas Pandruvada rb->buffer.data = kmalloc(length, GFP_KERNEL);
2143703f53bSSrinivas Pandruvada if (!rb->buffer.data)
2153703f53bSSrinivas Pandruvada return -ENOMEM;
2163703f53bSSrinivas Pandruvada
2173703f53bSSrinivas Pandruvada rb->buffer.size = length;
2183703f53bSSrinivas Pandruvada return 0;
2193703f53bSSrinivas Pandruvada }
2203703f53bSSrinivas Pandruvada
2213703f53bSSrinivas Pandruvada /**
2223703f53bSSrinivas Pandruvada * ishtp_cl_io_rb_recycle() - Recycle IO request blocks
2233703f53bSSrinivas Pandruvada * @rb: IO request block
2243703f53bSSrinivas Pandruvada *
2253703f53bSSrinivas Pandruvada * Re-append rb to its client's free list and send flow control if needed
2263703f53bSSrinivas Pandruvada *
2273703f53bSSrinivas Pandruvada * Return: 0 on success else -EFAULT
2283703f53bSSrinivas Pandruvada */
ishtp_cl_io_rb_recycle(struct ishtp_cl_rb * rb)2293703f53bSSrinivas Pandruvada int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
2303703f53bSSrinivas Pandruvada {
2313703f53bSSrinivas Pandruvada struct ishtp_cl *cl;
2323703f53bSSrinivas Pandruvada int rets = 0;
2333703f53bSSrinivas Pandruvada unsigned long flags;
2343703f53bSSrinivas Pandruvada
2353703f53bSSrinivas Pandruvada if (!rb || !rb->cl)
2363703f53bSSrinivas Pandruvada return -EFAULT;
2373703f53bSSrinivas Pandruvada
2383703f53bSSrinivas Pandruvada cl = rb->cl;
2393703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->free_list_spinlock, flags);
2403703f53bSSrinivas Pandruvada list_add_tail(&rb->list, &cl->free_rb_list.list);
2413703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
2423703f53bSSrinivas Pandruvada
2433703f53bSSrinivas Pandruvada /*
2443703f53bSSrinivas Pandruvada * If we returned the first buffer to empty 'free' list,
2453703f53bSSrinivas Pandruvada * send flow control
2463703f53bSSrinivas Pandruvada */
2473703f53bSSrinivas Pandruvada if (!cl->out_flow_ctrl_creds)
2483703f53bSSrinivas Pandruvada rets = ishtp_cl_read_start(cl);
2493703f53bSSrinivas Pandruvada
2503703f53bSSrinivas Pandruvada return rets;
2513703f53bSSrinivas Pandruvada }
2523703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
253a1c40ce6SEven Xu
254a1c40ce6SEven Xu /**
255a1c40ce6SEven Xu * ishtp_cl_tx_empty() -test whether client device tx buffer is empty
256a1c40ce6SEven Xu * @cl: Pointer to client device instance
257a1c40ce6SEven Xu *
258a1c40ce6SEven Xu * Look client device tx buffer list, and check whether this list is empty
259a1c40ce6SEven Xu *
260a1c40ce6SEven Xu * Return: true if client tx buffer list is empty else false
261a1c40ce6SEven Xu */
ishtp_cl_tx_empty(struct ishtp_cl * cl)262a1c40ce6SEven Xu bool ishtp_cl_tx_empty(struct ishtp_cl *cl)
263a1c40ce6SEven Xu {
264a1c40ce6SEven Xu int tx_list_empty;
265a1c40ce6SEven Xu unsigned long tx_flags;
266a1c40ce6SEven Xu
267a1c40ce6SEven Xu spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
268a1c40ce6SEven Xu tx_list_empty = list_empty(&cl->tx_list.list);
269a1c40ce6SEven Xu spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
270a1c40ce6SEven Xu
271a1c40ce6SEven Xu return !!tx_list_empty;
272a1c40ce6SEven Xu }
273a1c40ce6SEven Xu EXPORT_SYMBOL(ishtp_cl_tx_empty);
274a1c40ce6SEven Xu
275a1c40ce6SEven Xu /**
276a1c40ce6SEven Xu * ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list
277a1c40ce6SEven Xu * @cl: Pointer to client device instance
278a1c40ce6SEven Xu *
279a1c40ce6SEven Xu * Check client device in-processing buffer list and get a rb from it.
280a1c40ce6SEven Xu *
281a1c40ce6SEven Xu * Return: rb pointer if buffer list isn't empty else NULL
282a1c40ce6SEven Xu */
ishtp_cl_rx_get_rb(struct ishtp_cl * cl)283a1c40ce6SEven Xu struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl)
284a1c40ce6SEven Xu {
285a1c40ce6SEven Xu unsigned long rx_flags;
286a1c40ce6SEven Xu struct ishtp_cl_rb *rb;
287a1c40ce6SEven Xu
288a1c40ce6SEven Xu spin_lock_irqsave(&cl->in_process_spinlock, rx_flags);
289a1c40ce6SEven Xu rb = list_first_entry_or_null(&cl->in_process_list.list,
290a1c40ce6SEven Xu struct ishtp_cl_rb, list);
291a1c40ce6SEven Xu if (rb)
292a1c40ce6SEven Xu list_del_init(&rb->list);
293a1c40ce6SEven Xu spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags);
294a1c40ce6SEven Xu
295a1c40ce6SEven Xu return rb;
296a1c40ce6SEven Xu }
297a1c40ce6SEven Xu EXPORT_SYMBOL(ishtp_cl_rx_get_rb);
298