Root/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
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 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 */
306CsrResult 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 */
386CsrResult 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
423

Archive Download this file



interactive