Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
csr_wifi_hip_send.c
Go to the documentation of this file.
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"
25 #include "csr_wifi_hip_sigs.h"
26 #include "csr_wifi_hip_card.h"
27 
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 
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 
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): %*ph\n", siglen,
176  16, sig);
177  unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n",
178  bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL,
179  bulkdata != NULL?bulkdata->d[0].data_length : 0,
180  bulkdata != NULL?bulkdata->d[1].os_data_ptr : NULL,
181  bulkdata != NULL?bulkdata->d[1].data_length : 0);
182  }
183 
184  /* Advance the written count to say there is a new entry */
185  CSR_WIFI_HIP_Q_INC_W(sigq);
186 
187  /*
188  * Set the flag to say reason for waking was a host request.
189  * Then ask the OS layer to run the unifi_bh.
190  */
191  if (run_bh == 1)
192  {
193  card->bh_reason_host = 1;
194  r = unifi_run_bh(card->ospriv);
195  if (r != CSR_RESULT_SUCCESS)
196  {
197  unifi_error(card->ospriv, "failed to run bh.\n");
198  card->bh_reason_host = 0;
199 
200  /*
201  * The bulk data buffer will be freed by the caller.
202  * We need to invalidate the description of the bulk data in our
203  * soft queue, to prevent the core freeing the bulk data again later.
204  */
205  for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i)
206  {
207  if (csptr->bulkdata[i].data_length != 0)
208  {
209  csptr->bulkdata[i].os_data_ptr = csptr->bulkdata[i].os_net_buf_ptr = NULL;
210  csptr->bulkdata[i].net_buf_length = csptr->bulkdata[i].data_length = 0;
211  }
212  }
213  return r;
214  }
215  }
216  else
217  {
218  unifi_error(card->ospriv, "run_bh=%d, bh not called.\n", run_bh);
219  }
220 
221  /*
222  * Have we used up all the fh signal list entries?
223  */
224  if (CSR_WIFI_HIP_Q_SLOTS_FREE(sigq) == 0)
225  {
226  /* We have filled the queue, so stop the upper layer. The command queue
227  * is an exception, as suspending due to that being full could delay
228  * resume/retry until new commands or data are received.
229  */
230  if (sigq != &card->fh_command_queue)
231  {
232  /*
233  * Must call unifi_pause_xmit() *before* setting the paused flag.
234  * (the unifi_pause_xmit call should not be after setting the flag because of the possibility of being interrupted
235  * by the bh thread between our setting the flag and the call to unifi_pause_xmit()
236  * If bh thread then cleared the flag, we would end up paused, but without the flag set)
237  * Instead, setting it afterwards means that if this thread is interrupted by the bh thread
238  * the pause flag is still guaranteed to end up set
239  * However the potential deadlock now is that if bh thread emptied the queue and cleared the flag before this thread's
240  * call to unifi_pause_xmit(), then bh thread may not run again because it will be waiting for
241  * a packet to appear in the queue but nothing ever will because xmit is paused.
242  * 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.
243  * (Note even this bad situation would not persist long in practice, because something else (eg rx, or tx in different queue)
244  * is likely to wake bh thread quite soon)
245  * But to avoid this deadlock completely, after setting the flag we check that there is something left in the queue.
246  * If there is, we know that bh thread has not emptied the queue yet.
247  * Since bh thread checks to unpause the queue *after* taking packets from the queue, we know that it is still going to make at
248  * least one more check to see whether it needs to unpause the queue. So all is well.
249  * If there are no packets in the queue, then the deadlock described above might happen. To make sure it does not, we
250  * unpause the queue here. A possible side effect is that unifi_restart_xmit() may (rarely) be called for second time
251  * unnecessarily, which is harmless
252  */
253 
254 #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
255  unifi_debug_log_to_buf("P");
256 #endif
257  unifi_pause_xmit(card->ospriv, (unifi_TrafficQueue)priority_q);
258  card_tx_q_pause(card, priority_q);
259  if (CSR_WIFI_HIP_Q_SLOTS_USED(sigq) == 0)
260  {
261  card_tx_q_unpause(card, priority_q);
262  unifi_restart_xmit(card->ospriv, (unifi_TrafficQueue) priority_q);
263  }
264  }
265  else
266  {
267  unifi_warning(card->ospriv,
268  "send_signal: fh_cmd_q full, not pausing (run_bh=%d)\n",
269  run_bh);
270  }
271  }
272 
273  func_exit();
274 
275  return CSR_RESULT_SUCCESS;
276 } /* send_signal() */
277 
278 
279 /*
280  * ---------------------------------------------------------------------------
281  * unifi_send_signal
282  *
283  * Invokes send_signal() to queue a signal in the command or traffic queue
284  * If sigptr pointer is NULL, it pokes the bh to check if UniFi is responsive.
285  *
286  * Arguments:
287  * card Pointer to card context struct
288  * sigptr Pointer to signal from card.
289  * siglen Size of the signal
290  * bulkdata Pointer to the bulk data of the signal
291  *
292  * Returns:
293  * CSR_RESULT_SUCCESS on success
294  * CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or no free signal queue entry
295  *
296  * Notes:
297  * unifi_send_signal() is used to queue signals, created by the driver,
298  * to the device. Signals are constructed using the UniFi packed structures.
299  * ---------------------------------------------------------------------------
300  */
301 CsrResult unifi_send_signal(card_t *card, const u8 *sigptr, u32 siglen,
302  const bulk_data_param_t *bulkdata)
303 {
304  q_t *sig_soft_q;
305  u16 signal_id;
306  CsrResult r;
307  u32 run_bh;
308  u32 priority_q;
309 
310  /* A NULL signal pointer is a request to check if UniFi is responsive */
311  if (sigptr == NULL)
312  {
313  card->bh_reason_host = 1;
314  return unifi_run_bh(card->ospriv);
315  }
316 
317  priority_q = 0;
318  run_bh = 1;
319  signal_id = GET_SIGNAL_ID(sigptr);
320  /*
321  * If the signal is a CSR_MA_PACKET_REQUEST ,
322  * we send it using the traffic soft queue. Else we use the command soft queue.
323  */
324  if (signal_id == CSR_MA_PACKET_REQUEST_ID)
325  {
326  u16 frame_priority;
327 
328  if (card->periodic_wake_mode == UNIFI_PERIODIC_WAKE_HOST_ENABLED)
329  {
330  run_bh = 0;
331  }
332 
333 #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
334  unifi_debug_log_to_buf("D");
335 #endif
336  /* Sanity check: MA-PACKET.req must have a valid bulk data */
337  if ((bulkdata->d[0].data_length == 0) || (bulkdata->d[0].os_data_ptr == NULL))
338  {
339  unifi_error(card->ospriv, "MA-PACKET.req with empty bulk data (%d bytes in %p)\n",
340  bulkdata->d[0].data_length, bulkdata->d[0].os_data_ptr);
341  dump((void *)sigptr, siglen);
342  return CSR_RESULT_FAILURE;
343  }
344 
345  /* Map the frame priority to a traffic queue index. */
346  frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
347  priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
348 
349  sig_soft_q = &card->fh_traffic_queue[priority_q];
350  }
351  else
352  {
353  sig_soft_q = &card->fh_command_queue;
354  }
355 
356  r = send_signal(card, sigptr, siglen, bulkdata, sig_soft_q, priority_q, run_bh);
357  /* On error, the caller must free or requeue bulkdata buffers */
358 
359  return r;
360 } /* unifi_send_signal() */
361 
362 
363 /*
364  * ---------------------------------------------------------------------------
365  * unifi_send_resources_available
366  *
367  * Examines whether there is available space to queue
368  * a signal in the command or traffic queue
369  *
370  * Arguments:
371  * card Pointer to card context struct
372  * sigptr Pointer to signal.
373  *
374  * Returns:
375  * CSR_RESULT_SUCCESS if resources available
376  * CSR_WIFI_HIP_RESULT_NO_SPACE if there was no free signal queue entry
377  *
378  * Notes:
379  * ---------------------------------------------------------------------------
380  */
382 {
383  q_t *sig_soft_q;
384  u16 signal_id = GET_SIGNAL_ID(sigptr);
385 
386  /*
387  * If the signal is a CSR_MA_PACKET_REQUEST ,
388  * we send it using the traffic soft queue. Else we use the command soft queue.
389  */
390  if (signal_id == CSR_MA_PACKET_REQUEST_ID)
391  {
392  u16 frame_priority;
393  u32 priority_q;
394 
395  /* Map the frame priority to a traffic queue index. */
396  frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
397  priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);
398 
399  sig_soft_q = &card->fh_traffic_queue[priority_q];
400  }
401  else
402  {
403  sig_soft_q = &card->fh_command_queue;
404  }
405 
406  /* Check that the fh_data_queue has a free slot */
407  if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sig_soft_q))
408  {
409  unifi_notice(card->ospriv, "unifi_send_resources_available: %s full\n",
410  sig_soft_q->name);
412  }
413 
414  return CSR_RESULT_SUCCESS;
415 } /* unifi_send_resources_available() */
416 
417