]> Pileus Git - ~andy/linux/blob - drivers/staging/csr/csr_wifi_hip_send.c
Merge branches 'acpica', 'acpidump', 'intel-idle', 'misc', 'module_acpi_driver-simpli...
[~andy/linux] / drivers / staging / csr / csr_wifi_hip_send.c
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
28 unifi_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
51 CSR_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  */
103 static CsrResult send_signal(card_t *card, const u8 *sigptr, u32 siglen,
104                              const bulk_data_param_t *bulkdata,
105                              q_t *sigq, u32 priority_q, u32 run_bh)
106 {
107     u16 i, data_slot_size;
108     card_signal_t *csptr;
109     s16 qe;
110     CsrResult r;
111     s16 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 = (u16)siglen;
132     memcpy((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             u32 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 = (u8 *)bulkdata->d[i].os_data_ptr;
160                 csptr->bulkdata[i].os_net_buf_ptr = (u8 *)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 u8 *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  */
306 CsrResult unifi_send_signal(card_t *card, const u8 *sigptr, u32 siglen,
307                             const bulk_data_param_t *bulkdata)
308 {
309     q_t *sig_soft_q;
310     u16 signal_id;
311     CsrResult r;
312     u32 run_bh;
313     u32 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         u16 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  */
386 CsrResult unifi_send_resources_available(card_t *card, const u8 *sigptr)
387 {
388     q_t *sig_soft_q;
389     u16 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         u16 frame_priority;
398         u32 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