298 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ISHTP Ring Buffers4 *5 * Copyright (c) 2003-2016, Intel Corporation.6 */7 8#include <linux/slab.h>9#include "client.h"10 11/**12 * ishtp_cl_alloc_rx_ring() - Allocate RX ring buffers13 * @cl: client device instance14 *15 * Allocate and initialize RX ring buffers16 *17 * Return: 0 on success else -ENOMEM18 */19int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl)20{21 size_t len = cl->device->fw_client->props.max_msg_length;22 int j;23 struct ishtp_cl_rb *rb;24 int ret = 0;25 unsigned long flags;26 27 for (j = 0; j < cl->rx_ring_size; ++j) {28 rb = ishtp_io_rb_init(cl);29 if (!rb) {30 ret = -ENOMEM;31 goto out;32 }33 ret = ishtp_io_rb_alloc_buf(rb, len);34 if (ret)35 goto out;36 spin_lock_irqsave(&cl->free_list_spinlock, flags);37 list_add_tail(&rb->list, &cl->free_rb_list.list);38 spin_unlock_irqrestore(&cl->free_list_spinlock, flags);39 }40 41 return 0;42 43out:44 dev_err(&cl->device->dev, "error in allocating Rx buffers\n");45 ishtp_cl_free_rx_ring(cl);46 return ret;47}48 49/**50 * ishtp_cl_alloc_tx_ring() - Allocate TX ring buffers51 * @cl: client device instance52 *53 * Allocate and initialize TX ring buffers54 *55 * Return: 0 on success else -ENOMEM56 */57int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)58{59 size_t len = cl->device->fw_client->props.max_msg_length;60 int j;61 unsigned long flags;62 63 cl->tx_ring_free_size = 0;64 65 /* Allocate pool to free Tx bufs */66 for (j = 0; j < cl->tx_ring_size; ++j) {67 struct ishtp_cl_tx_ring *tx_buf;68 69 tx_buf = kzalloc(sizeof(struct ishtp_cl_tx_ring), GFP_KERNEL);70 if (!tx_buf)71 goto out;72 73 tx_buf->send_buf.data = kmalloc(len, GFP_KERNEL);74 if (!tx_buf->send_buf.data) {75 kfree(tx_buf);76 goto out;77 }78 79 spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);80 list_add_tail(&tx_buf->list, &cl->tx_free_list.list);81 ++cl->tx_ring_free_size;82 spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);83 }84 return 0;85out:86 dev_err(&cl->device->dev, "error in allocating Tx pool\n");87 ishtp_cl_free_tx_ring(cl);88 return -ENOMEM;89}90 91/**92 * ishtp_cl_free_rx_ring() - Free RX ring buffers93 * @cl: client device instance94 *95 * Free RX ring buffers96 */97void ishtp_cl_free_rx_ring(struct ishtp_cl *cl)98{99 struct ishtp_cl_rb *rb;100 unsigned long flags;101 102 /* release allocated memory - pass over free_rb_list */103 spin_lock_irqsave(&cl->free_list_spinlock, flags);104 while (!list_empty(&cl->free_rb_list.list)) {105 rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb,106 list);107 list_del(&rb->list);108 kfree(rb->buffer.data);109 kfree(rb);110 }111 spin_unlock_irqrestore(&cl->free_list_spinlock, flags);112 /* release allocated memory - pass over in_process_list */113 spin_lock_irqsave(&cl->in_process_spinlock, flags);114 while (!list_empty(&cl->in_process_list.list)) {115 rb = list_entry(cl->in_process_list.list.next,116 struct ishtp_cl_rb, list);117 list_del(&rb->list);118 kfree(rb->buffer.data);119 kfree(rb);120 }121 spin_unlock_irqrestore(&cl->in_process_spinlock, flags);122}123 124/**125 * ishtp_cl_free_tx_ring() - Free TX ring buffers126 * @cl: client device instance127 *128 * Free TX ring buffers129 */130void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)131{132 struct ishtp_cl_tx_ring *tx_buf;133 unsigned long flags;134 135 spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);136 /* release allocated memory - pass over tx_free_list */137 while (!list_empty(&cl->tx_free_list.list)) {138 tx_buf = list_entry(cl->tx_free_list.list.next,139 struct ishtp_cl_tx_ring, list);140 list_del(&tx_buf->list);141 --cl->tx_ring_free_size;142 kfree(tx_buf->send_buf.data);143 kfree(tx_buf);144 }145 spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);146 147 spin_lock_irqsave(&cl->tx_list_spinlock, flags);148 /* release allocated memory - pass over tx_list */149 while (!list_empty(&cl->tx_list.list)) {150 tx_buf = list_entry(cl->tx_list.list.next,151 struct ishtp_cl_tx_ring, list);152 list_del(&tx_buf->list);153 kfree(tx_buf->send_buf.data);154 kfree(tx_buf);155 }156 spin_unlock_irqrestore(&cl->tx_list_spinlock, flags);157}158 159/**160 * ishtp_io_rb_free() - Free IO request block161 * @rb: IO request block162 *163 * Free io request block memory164 */165void ishtp_io_rb_free(struct ishtp_cl_rb *rb)166{167 if (rb == NULL)168 return;169 170 kfree(rb->buffer.data);171 kfree(rb);172}173 174/**175 * ishtp_io_rb_init() - Allocate and init IO request block176 * @cl: client device instance177 *178 * Allocate and initialize request block179 *180 * Return: Allocted IO request block pointer181 */182struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl)183{184 struct ishtp_cl_rb *rb;185 186 rb = kzalloc(sizeof(struct ishtp_cl_rb), GFP_KERNEL);187 if (!rb)188 return NULL;189 190 INIT_LIST_HEAD(&rb->list);191 rb->cl = cl;192 rb->buf_idx = 0;193 return rb;194}195 196/**197 * ishtp_io_rb_alloc_buf() - Allocate and init response buffer198 * @rb: IO request block199 * @length: length of response buffer200 *201 * Allocate respose buffer202 *203 * Return: 0 on success else -ENOMEM204 */205int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length)206{207 if (!rb)208 return -EINVAL;209 210 if (length == 0)211 return 0;212 213 rb->buffer.data = kmalloc(length, GFP_KERNEL);214 if (!rb->buffer.data)215 return -ENOMEM;216 217 rb->buffer.size = length;218 return 0;219}220 221/**222 * ishtp_cl_io_rb_recycle() - Recycle IO request blocks223 * @rb: IO request block224 *225 * Re-append rb to its client's free list and send flow control if needed226 *227 * Return: 0 on success else -EFAULT228 */229int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)230{231 struct ishtp_cl *cl;232 int rets = 0;233 unsigned long flags;234 235 if (!rb || !rb->cl)236 return -EFAULT;237 238 cl = rb->cl;239 spin_lock_irqsave(&cl->free_list_spinlock, flags);240 list_add_tail(&rb->list, &cl->free_rb_list.list);241 spin_unlock_irqrestore(&cl->free_list_spinlock, flags);242 243 /*244 * If we returned the first buffer to empty 'free' list,245 * send flow control246 */247 if (!cl->out_flow_ctrl_creds)248 rets = ishtp_cl_read_start(cl);249 250 return rets;251}252EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);253 254/**255 * ishtp_cl_tx_empty() -test whether client device tx buffer is empty256 * @cl: Pointer to client device instance257 *258 * Look client device tx buffer list, and check whether this list is empty259 *260 * Return: true if client tx buffer list is empty else false261 */262bool ishtp_cl_tx_empty(struct ishtp_cl *cl)263{264 int tx_list_empty;265 unsigned long tx_flags;266 267 spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);268 tx_list_empty = list_empty(&cl->tx_list.list);269 spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);270 271 return !!tx_list_empty;272}273EXPORT_SYMBOL(ishtp_cl_tx_empty);274 275/**276 * ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list277 * @cl: Pointer to client device instance278 *279 * Check client device in-processing buffer list and get a rb from it.280 *281 * Return: rb pointer if buffer list isn't empty else NULL282 */283struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl)284{285 unsigned long rx_flags;286 struct ishtp_cl_rb *rb;287 288 spin_lock_irqsave(&cl->in_process_spinlock, rx_flags);289 rb = list_first_entry_or_null(&cl->in_process_list.list,290 struct ishtp_cl_rb, list);291 if (rb)292 list_del_init(&rb->list);293 spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags);294 295 return rb;296}297EXPORT_SYMBOL(ishtp_cl_rx_get_rb);298