aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/csr/csr_wifi_hip_send.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-19 19:15:42 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-19 19:37:01 -0400
commit635d2b00e5070378e7bf812acf47fb135c6ab928 (patch)
tree7048a0a511f3d221aa2dfe40aa3a401991f1b175 /drivers/staging/csr/csr_wifi_hip_send.c
parent15a4bc17b7f4e85cb019e683f14e834078ec2208 (diff)
Staging: add CSR wifi module
This consists of two modules, the driver, and a "helper" module that is just a wrapper around common kernel functions. The wrapper module will be removed soon, but for now it's needed. These files were based on the csr-linux-wifi-5.0.3-oss.tar.gz package provided by CSR and Blue Giga, and is covered under the license specified in the LICENSE.txt file (basically dual BSD and GPLv2). The files were flattened out of the deep directory mess they were originally in, and a few EXPORT_SYMBOL_GPL() were added in order for everything to link properly with the helper module setup. Cc: Mikko Virkkilä <mikko.virkkila@bluegiga.com> Cc: Lauri Hintsala <Lauri.Hintsala@bluegiga.com> Cc: Riku Mettälä <riku.mettala@bluegiga.com> Cc: Veli-Pekka Peltola <veli-pekka.peltola@bluegiga.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/csr/csr_wifi_hip_send.c')
-rw-r--r--drivers/staging/csr/csr_wifi_hip_send.c422
1 files changed, 422 insertions, 0 deletions
diff --git a/drivers/staging/csr/csr_wifi_hip_send.c b/drivers/staging/csr/csr_wifi_hip_send.c
new file mode 100644
index 00000000000..624f3bb3712
--- /dev/null
+++ b/drivers/staging/csr/csr_wifi_hip_send.c
@@ -0,0 +1,422 @@
1/*****************************************************************************
2
3 (c) Cambridge Silicon Radio Limited 2011
4 All rights reserved and confidential information of CSR
5
6 Refer to LICENSE.txt included with this source for details
7 on the license terms.
8
9*****************************************************************************/
10
11/*
12 * ***************************************************************************
13 *
14 * FILE: csr_wifi_hip_send.c
15 *
16 * PURPOSE:
17 * Code for adding a signal request to the from-host queue.
18 * When the driver bottom-half is run, it will take requests from the
19 * queue and pass them to the UniFi.
20 *
21 * ***************************************************************************
22 */
23#include "csr_wifi_hip_unifi.h"
24#include "csr_wifi_hip_conversions.h"
25#include "csr_wifi_hip_sigs.h"
26#include "csr_wifi_hip_card.h"
27
28unifi_TrafficQueue unifi_frame_priority_to_queue(CSR_PRIORITY priority)
29{
30 switch (priority)
31 {
32 case CSR_QOS_UP0:
33 case CSR_QOS_UP3:
34 return UNIFI_TRAFFIC_Q_BE;
35 case CSR_QOS_UP1:
36 case CSR_QOS_UP2:
37 return UNIFI_TRAFFIC_Q_BK;
38 case CSR_QOS_UP4:
39 case CSR_QOS_UP5:
40 return UNIFI_TRAFFIC_Q_VI;
41 case CSR_QOS_UP6:
42 case CSR_QOS_UP7:
43 case CSR_MANAGEMENT:
44 return UNIFI_TRAFFIC_Q_VO;
45 default:
46 return UNIFI_TRAFFIC_Q_BE;
47 }
48}
49
50
51CSR_PRIORITY unifi_get_default_downgrade_priority(unifi_TrafficQueue queue)
52{
53 switch (queue)
54 {
55 case UNIFI_TRAFFIC_Q_BE:
56 return CSR_QOS_UP0;
57 case UNIFI_TRAFFIC_Q_BK:
58 return CSR_QOS_UP1;
59 case UNIFI_TRAFFIC_Q_VI:
60 return CSR_QOS_UP5;
61 case UNIFI_TRAFFIC_Q_VO:
62 return CSR_QOS_UP6;
63 default:
64 return CSR_QOS_UP0;
65 }
66}
67
68
69/*
70 * ---------------------------------------------------------------------------
71 * send_signal
72 *
73 * This function queues a signal for sending to UniFi. It first checks
74 * that there is space on the fh_signal_queue for another entry, then
75 * claims any bulk data slots required and copies data into them. Then
76 * increments the fh_signal_queue write count.
77 *
78 * The fh_signal_queue is later processed by the driver bottom half
79 * (in unifi_bh()).
80 *
81 * This function call unifi_pause_xmit() to pause the flow of data plane
82 * packets when:
83 * - the fh_signal_queue ring buffer is full
84 * - there are less than UNIFI_MAX_DATA_REFERENCES (2) bulk data
85 * slots available.
86 *
87 * Arguments:
88 * card Pointer to card context structure
89 * sigptr Pointer to the signal to write to UniFi.
90 * siglen Number of bytes pointer to by sigptr.
91 * bulkdata Array of pointers to an associated bulk data.
92 * sigq To which from-host queue to add the signal.
93 *
94 * Returns:
95 * CSR_RESULT_SUCCESS on success
96 * CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or
97 * no free signal queue entry
98 *
99 * Notes:
100 * Calls unifi_pause_xmit() when the last slots are used.
101 * ---------------------------------------------------------------------------
102 */
103static CsrResult send_signal(card_t *card, const CsrUint8 *sigptr, CsrUint32 siglen,
104 const bulk_data_param_t *bulkdata,
105 q_t *sigq, CsrUint32 priority_q, CsrUint32 run_bh)
106{
107 CsrUint16 i, data_slot_size;
108 card_signal_t *csptr;
109 CsrInt16 qe;
110 CsrResult r;
111 CsrInt16 debug_print = 0;
112
113 data_slot_size = CardGetDataSlotSize(card);
114
115 /* Check that the fh_data_queue has a free slot */
116 if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sigq))
117 {
118 unifi_trace(card->ospriv, UDBG3, "send_signal: %s full\n", sigq->name);
119
120 return CSR_WIFI_HIP_RESULT_NO_SPACE;
121 }
122
123 /*
124 * Now add the signal to the From Host signal queue
125 */
126 /* Get next slot on queue */
127 qe = CSR_WIFI_HIP_Q_NEXT_W_SLOT(sigq);
128 csptr = CSR_WIFI_HIP_Q_SLOT_DATA(sigq, qe);
129
130 /* Make up the card_signal struct */
131 csptr->signal_length = (CsrUint16)siglen;
132 CsrMemCpy((void *)csptr->sigbuf, (void *)sigptr, siglen);
133
134 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
135 {
136 if ((bulkdata != NULL) && (bulkdata->d[i].data_length != 0))
137 {
138 CsrUint32 datalen = bulkdata->d[i].data_length;
139
140 /* Make sure data will fit in a bulk data slot */
141 if (bulkdata->d[i].os_data_ptr == NULL)
142 {
143 unifi_error(card->ospriv, "send_signal - NULL bulkdata[%d]\n", i);
144 debug_print++;
145 csptr->bulkdata[i].data_length = 0;
146 }
147 else
148 {
149 if (datalen > data_slot_size)
150 {
151 unifi_error(card->ospriv,
152 "send_signal - Invalid data length %u (@%p), "
153 "truncating\n",
154 datalen, bulkdata->d[i].os_data_ptr);
155 datalen = data_slot_size;
156 debug_print++;
157 }
158 /* Store the bulk data info in the soft queue. */
159 csptr->bulkdata[i].os_data_ptr = (CsrUint8 *)bulkdata->d[i].os_data_ptr;
160 csptr->bulkdata[i].os_net_buf_ptr = (CsrUint8 *)bulkdata->d[i].os_net_buf_ptr;
161 csptr->bulkdata[i].net_buf_length = bulkdata->d[i].net_buf_length;
162 csptr->bulkdata[i].data_length = datalen;
163 }
164 }
165 else
166 {
167 UNIFI_INIT_BULK_DATA(&csptr->bulkdata[i]);
168 }
169 }
170
171 if (debug_print)
172 {
173 const CsrUint8 *sig = sigptr;
174
175 unifi_error(card->ospriv, "Signal(%d): %02x %02x %02x %02x %02x %02x %02x %02x"
176 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
177 siglen,
178 sig[0], sig[1], sig[2], sig[3],
179 sig[4], sig[5], sig[6], sig[7],
180 sig[8], sig[9], sig[10], sig[11],
181 sig[12], sig[13], sig[14], sig[15]);
182 unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n",
183 bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL,
184 bulkdata != NULL?bulkdata->d[0].data_length : 0,
185 bulkdata != NULL?bulkdata->d[1].os_data_ptr : NULL,
186 bulkdata != NULL?bulkdata->d[1].data_length : 0);
187 }
188
189 /* Advance the written count to say there is a new entry */
190 CSR_WIFI_HIP_Q_INC_W(sigq);
191
192 /*
193 * Set the flag to say reason for waking was a host request.
194 * Then ask the OS layer to run the unifi_bh.
195 */
196 if (run_bh == 1)
197 {
198 card->bh_reason_host = 1;
199 r = unifi_run_bh(card->ospriv);
200 if (r != CSR_RESULT_SUCCESS)
201 {
202 unifi_error(card->ospriv, "failed to run bh.\n");
203 card->bh_reason_host = 0;
204
205 /*
206 * The bulk data buffer will be freed by the caller.
207 * We need to invalidate the description of the bulk data in our
208 * soft queue, to prevent the core freeing the bulk data again later.
209 */
210 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
211 {
212 if (csptr->bulkdata[i].data_length != 0)
213 {
214 csptr->bulkdata[i].os_data_ptr = csptr->bulkdata[i].os_net_buf_ptr = NULL;
215 csptr->bulkdata[i].net_buf_length = csptr->bulkdata[i].data_length = 0;
216 }
217 }
218 return r;
219 }
220 }
221 else
222 {
223 unifi_error(card->ospriv, "run_bh=%d, bh not called.\n", run_bh);
224 }
225
226 /*
227 * Have we used up all the fh signal list entries?
228 */
229 if (CSR_WIFI_HIP_Q_SLOTS_FREE(sigq) == 0)
230 {
231 /* We have filled the queue, so stop the upper layer. The command queue
232 * is an exception, as suspending due to that being full could delay
233 * resume/retry until new commands or data are received.
234 */
235 if (sigq != &card->fh_command_queue)
236 {
237 /*
238 * Must call unifi_pause_xmit() *before* setting the paused flag.
239 * (the unifi_pause_xmit call should not be after setting the flag because of the possibility of being interrupted
240 * by the bh thread between our setting the flag and the call to unifi_pause_xmit()
241 * If bh thread then cleared the flag, we would end up paused, but without the flag set)
242 * Instead, setting it afterwards means that if this thread is interrupted by the bh thread
243 * the pause flag is still guaranteed to end up set
244 * However the potential deadlock now is that if bh thread emptied the queue and cleared the flag before this thread's
245 * call to unifi_pause_xmit(), then bh thread may not run again because it will be waiting for
246 * a packet to appear in the queue but nothing ever will because xmit is paused.
247 * So we will end up with the queue paused, and the flag set to say it is paused, but bh never runs to unpause it.
248 * (Note even this bad situation would not persist long in practice, because something else (eg rx, or tx in different queue)
249 * is likely to wake bh thread quite soon)
250 * But to avoid this deadlock completely, after setting the flag we check that there is something left in the queue.
251 * If there is, we know that bh thread has not emptied the queue yet.
252 * Since bh thread checks to unpause the queue *after* taking packets from the queue, we know that it is still going to make at
253 * least one more check to see whether it needs to unpause the queue. So all is well.
254 * If there are no packets in the queue, then the deadlock described above might happen. To make sure it does not, we
255 * unpause the queue here. A possible side effect is that unifi_restart_xmit() may (rarely) be called for second time
256 * unnecessarily, which is harmless
257 */
258
259#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
260 unifi_debug_log_to_buf("P");
261#endif
262 unifi_pause_xmit(card->ospriv, (unifi_TrafficQueue)priority_q);
263 card_tx_q_pause(card, priority_q);
264 if (CSR_WIFI_HIP_Q_SLOTS_USED(sigq) == 0)
265 {
266 card_tx_q_unpause(card, priority_q);
267 unifi_restart_xmit(card->ospriv, (unifi_TrafficQueue) priority_q);
268 }
269 }
270 else
271 {
272 unifi_warning(card->ospriv,
273 "send_signal: fh_cmd_q full, not pausing (run_bh=%d)\n",
274 run_bh);
275 }
276 }
277
278 func_exit();
279
280 return CSR_RESULT_SUCCESS;
281} /* send_signal() */
282
283
284/*
285 * ---------------------------------------------------------------------------
286 * unifi_send_signal
287 *
288 * Invokes send_signal() to queue a signal in the command or traffic queue
289 * If sigptr pointer is NULL, it pokes the bh to check if UniFi is responsive.
290 *
291 * Arguments:
292 * card Pointer to card context struct
293 * sigptr Pointer to signal from card.
294 * siglen Size of the signal
295 * bulkdata Pointer to the bulk data of the signal
296 *
297 * Returns:
298 * CSR_RESULT_SUCCESS on success
299 * CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or no free signal queue entry
300 *
301 * Notes:
302 * unifi_send_signal() is used to queue signals, created by the driver,
303 * to the device. Signals are constructed using the UniFi packed structures.
304 * ---------------------------------------------------------------------------
305 */
306CsrResult unifi_send_signal(card_t *card, const CsrUint8 *sigptr, CsrUint32 siglen,
307 const bulk_data_param_t *bulkdata)
308{
309 q_t *sig_soft_q;
310 CsrUint16 signal_id;
311 CsrResult r;
312 CsrUint32 run_bh;
313 CsrUint32 priority_q;
314
315 /* A NULL signal pointer is a request to check if UniFi is responsive */
316 if (sigptr == NULL)
317 {
318 card->bh_reason_host = 1;
319 return unifi_run_bh(card->ospriv);
320 }
321
322 priority_q = 0;
323 run_bh = 1;
324 signal_id = GET_SIGNAL_ID(sigptr);
325 /*
326 * If the signal is a CSR_MA_PACKET_REQUEST ,
327 * we send it using the traffic soft queue. Else we use the command soft queue.
328 */
329 if (signal_id == CSR_MA_PACKET_REQUEST_ID)
330 {
331 CsrUint16 frame_priority;
332
333 if (card->periodic_wake_mode == UNIFI_PERIODIC_WAKE_HOST_ENABLED)
334 {
335 run_bh = 0;
336 }
337
338#if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
339 unifi_debug_log_to_buf("D");
340#endif
341 /* Sanity check: MA-PACKET.req must have a valid bulk data */
342 if ((bulkdata->d[0].data_length == 0) || (bulkdata->d[0].os_data_ptr == NULL))
343 {
344 unifi_error(card->ospriv, "MA-PACKET.req with empty bulk data (%d bytes in %p)\n",
345 bulkdata->d[0].data_length, bulkdata->d[0].os_data_ptr);
346 dump((void *)sigptr, siglen);
347 return CSR_RESULT_FAILURE;
348 }
349
350 /* Map the frame priority to a traffic queue index. */
351 frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
352 priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
353
354 sig_soft_q = &card->fh_traffic_queue[priority_q];
355 }
356 else
357 {
358 sig_soft_q = &card->fh_command_queue;
359 }
360
361 r = send_signal(card, sigptr, siglen, bulkdata, sig_soft_q, priority_q, run_bh);
362 /* On error, the caller must free or requeue bulkdata buffers */
363
364 return r;
365} /* unifi_send_signal() */
366
367
368/*
369 * ---------------------------------------------------------------------------
370 * unifi_send_resources_available
371 *
372 * Examines whether there is available space to queue
373 * a signal in the command or traffic queue
374 *
375 * Arguments:
376 * card Pointer to card context struct
377 * sigptr Pointer to signal.
378 *
379 * Returns:
380 * CSR_RESULT_SUCCESS if resources available
381 * CSR_WIFI_HIP_RESULT_NO_SPACE if there was no free signal queue entry
382 *
383 * Notes:
384 * ---------------------------------------------------------------------------
385 */
386CsrResult unifi_send_resources_available(card_t *card, const CsrUint8 *sigptr)
387{
388 q_t *sig_soft_q;
389 CsrUint16 signal_id = GET_SIGNAL_ID(sigptr);
390
391 /*
392 * If the signal is a CSR_MA_PACKET_REQUEST ,
393 * we send it using the traffic soft queue. Else we use the command soft queue.
394 */
395 if (signal_id == CSR_MA_PACKET_REQUEST_ID)
396 {
397 CsrUint16 frame_priority;
398 CsrUint32 priority_q;
399
400 /* Map the frame priority to a traffic queue index. */
401 frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
402 priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
403
404 sig_soft_q = &card->fh_traffic_queue[priority_q];
405 }
406 else
407 {
408 sig_soft_q = &card->fh_command_queue;
409 }
410
411 /* Check that the fh_data_queue has a free slot */
412 if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sig_soft_q))
413 {
414 unifi_notice(card->ospriv, "unifi_send_resources_available: %s full\n",
415 sig_soft_q->name);
416 return CSR_WIFI_HIP_RESULT_NO_SPACE;
417 }
418
419 return CSR_RESULT_SUCCESS;
420} /* unifi_send_resources_available() */
421
422