1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * ISHTP Ring Buffers
4 *
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 buffers
13 * @cl: client device instance
14 *
15 * Allocate and initialize RX ring buffers
16 *
17 * Return: 0 on success else -ENOMEM
18 */
ishtp_cl_alloc_rx_ring(struct ishtp_cl * cl)19 int 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
43 out:
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 buffers
51 * @cl: client device instance
52 *
53 * Allocate and initialize TX ring buffers
54 *
55 * Return: 0 on success else -ENOMEM
56 */
ishtp_cl_alloc_tx_ring(struct ishtp_cl * cl)57 int 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;
85 out:
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 buffers
93 * @cl: client device instance
94 *
95 * Free RX ring buffers
96 */
ishtp_cl_free_rx_ring(struct ishtp_cl * cl)97 void 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 buffers
126 * @cl: client device instance
127 *
128 * Free TX ring buffers
129 */
ishtp_cl_free_tx_ring(struct ishtp_cl * cl)130 void 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 block
161 * @rb: IO request block
162 *
163 * Free io request block memory
164 */
ishtp_io_rb_free(struct ishtp_cl_rb * rb)165 void 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 block
176 * @cl: client device instance
177 *
178 * Allocate and initialize request block
179 *
180 * Return: Allocted IO request block pointer
181 */
ishtp_io_rb_init(struct ishtp_cl * cl)182 struct 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 buffer
198 * @rb: IO request block
199 * @length: length of response buffer
200 *
201 * Allocate respose buffer
202 *
203 * Return: 0 on success else -ENOMEM
204 */
ishtp_io_rb_alloc_buf(struct ishtp_cl_rb * rb,size_t length)205 int 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 blocks
223 * @rb: IO request block
224 *
225 * Re-append rb to its client's free list and send flow control if needed
226 *
227 * Return: 0 on success else -EFAULT
228 */
ishtp_cl_io_rb_recycle(struct ishtp_cl_rb * rb)229 int 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 control
246 */
247 if (!cl->out_flow_ctrl_creds)
248 rets = ishtp_cl_read_start(cl);
249
250 return rets;
251 }
252 EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
253
254 /**
255 * ishtp_cl_tx_empty() -test whether client device tx buffer is empty
256 * @cl: Pointer to client device instance
257 *
258 * Look client device tx buffer list, and check whether this list is empty
259 *
260 * Return: true if client tx buffer list is empty else false
261 */
ishtp_cl_tx_empty(struct ishtp_cl * cl)262 bool 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 }
273 EXPORT_SYMBOL(ishtp_cl_tx_empty);
274
275 /**
276 * ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list
277 * @cl: Pointer to client device instance
278 *
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 NULL
282 */
ishtp_cl_rx_get_rb(struct ishtp_cl * cl)283 struct 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 }
297 EXPORT_SYMBOL(ishtp_cl_rx_get_rb);
298