1 /*****************************************************************************
3 (c) Cambridge Silicon Radio Limited 2011
4 All rights reserved and confidential information of CSR
6 Refer to LICENSE.txt included with this source for details
9 *****************************************************************************/
12 * ***************************************************************************
14 * FILE: csr_wifi_hip_send.c
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.
21 * ***************************************************************************
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"
28 unifi_TrafficQueue
unifi_frame_priority_to_queue(CSR_PRIORITY priority
)
34 return UNIFI_TRAFFIC_Q_BE
;
37 return UNIFI_TRAFFIC_Q_BK
;
40 return UNIFI_TRAFFIC_Q_VI
;
44 return UNIFI_TRAFFIC_Q_VO
;
46 return UNIFI_TRAFFIC_Q_BE
;
51 CSR_PRIORITY
unifi_get_default_downgrade_priority(unifi_TrafficQueue queue
)
55 case UNIFI_TRAFFIC_Q_BE
:
57 case UNIFI_TRAFFIC_Q_BK
:
59 case UNIFI_TRAFFIC_Q_VI
:
61 case UNIFI_TRAFFIC_Q_VO
:
70 * ---------------------------------------------------------------------------
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.
78 * The fh_signal_queue is later processed by the driver bottom half
81 * This function call unifi_pause_xmit() to pause the flow of data plane
83 * - the fh_signal_queue ring buffer is full
84 * - there are less than UNIFI_MAX_DATA_REFERENCES (2) bulk data
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.
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
100 * Calls unifi_pause_xmit() when the last slots are used.
101 * ---------------------------------------------------------------------------
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
)
107 u16 i
, data_slot_size
;
108 card_signal_t
*csptr
;
113 data_slot_size
= CardGetDataSlotSize(card
);
115 /* Check that the fh_data_queue has a free slot */
116 if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sigq
))
118 unifi_trace(card
->ospriv
, UDBG3
, "send_signal: %s full\n", sigq
->name
);
120 return CSR_WIFI_HIP_RESULT_NO_SPACE
;
124 * Now add the signal to the From Host signal queue
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
);
130 /* Make up the card_signal struct */
131 csptr
->signal_length
= (u16
)siglen
;
132 memcpy((void *)csptr
->sigbuf
, (void *)sigptr
, siglen
);
134 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; ++i
)
136 if ((bulkdata
!= NULL
) && (bulkdata
->d
[i
].data_length
!= 0))
138 u32 datalen
= bulkdata
->d
[i
].data_length
;
140 /* Make sure data will fit in a bulk data slot */
141 if (bulkdata
->d
[i
].os_data_ptr
== NULL
)
143 unifi_error(card
->ospriv
, "send_signal - NULL bulkdata[%d]\n", i
);
145 csptr
->bulkdata
[i
].data_length
= 0;
149 if (datalen
> data_slot_size
)
151 unifi_error(card
->ospriv
,
152 "send_signal - Invalid data length %u (@%p), "
154 datalen
, bulkdata
->d
[i
].os_data_ptr
);
155 datalen
= data_slot_size
;
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
;
167 UNIFI_INIT_BULK_DATA(&csptr
->bulkdata
[i
]);
173 const u8
*sig
= sigptr
;
175 unifi_error(card
->ospriv
, "Signal(%d): %*ph\n", siglen
,
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);
184 /* Advance the written count to say there is a new entry */
185 CSR_WIFI_HIP_Q_INC_W(sigq
);
188 * Set the flag to say reason for waking was a host request.
189 * Then ask the OS layer to run the unifi_bh.
193 card
->bh_reason_host
= 1;
194 r
= unifi_run_bh(card
->ospriv
);
195 if (r
!= CSR_RESULT_SUCCESS
)
197 unifi_error(card
->ospriv
, "failed to run bh.\n");
198 card
->bh_reason_host
= 0;
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.
205 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; ++i
)
207 if (csptr
->bulkdata
[i
].data_length
!= 0)
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;
218 unifi_error(card
->ospriv
, "run_bh=%d, bh not called.\n", run_bh
);
222 * Have we used up all the fh signal list entries?
224 if (CSR_WIFI_HIP_Q_SLOTS_FREE(sigq
) == 0)
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.
230 if (sigq
!= &card
->fh_command_queue
)
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
254 #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
255 unifi_debug_log_to_buf("P");
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)
261 card_tx_q_unpause(card
, priority_q
);
262 unifi_restart_xmit(card
->ospriv
, (unifi_TrafficQueue
) priority_q
);
267 unifi_warning(card
->ospriv
,
268 "send_signal: fh_cmd_q full, not pausing (run_bh=%d)\n",
273 return CSR_RESULT_SUCCESS
;
274 } /* send_signal() */
278 * ---------------------------------------------------------------------------
281 * Invokes send_signal() to queue a signal in the command or traffic queue
282 * If sigptr pointer is NULL, it pokes the bh to check if UniFi is responsive.
285 * card Pointer to card context struct
286 * sigptr Pointer to signal from card.
287 * siglen Size of the signal
288 * bulkdata Pointer to the bulk data of the signal
291 * CSR_RESULT_SUCCESS on success
292 * CSR_WIFI_HIP_RESULT_NO_SPACE if there were insufficient data slots or no free signal queue entry
295 * unifi_send_signal() is used to queue signals, created by the driver,
296 * to the device. Signals are constructed using the UniFi packed structures.
297 * ---------------------------------------------------------------------------
299 CsrResult
unifi_send_signal(card_t
*card
, const u8
*sigptr
, u32 siglen
,
300 const bulk_data_param_t
*bulkdata
)
308 /* A NULL signal pointer is a request to check if UniFi is responsive */
311 card
->bh_reason_host
= 1;
312 return unifi_run_bh(card
->ospriv
);
317 signal_id
= GET_SIGNAL_ID(sigptr
);
319 * If the signal is a CSR_MA_PACKET_REQUEST ,
320 * we send it using the traffic soft queue. Else we use the command soft queue.
322 if (signal_id
== CSR_MA_PACKET_REQUEST_ID
)
326 if (card
->periodic_wake_mode
== UNIFI_PERIODIC_WAKE_HOST_ENABLED
)
331 #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) && defined (CSR_WIFI_HIP_DATA_PLANE_PROFILE)
332 unifi_debug_log_to_buf("D");
334 /* Sanity check: MA-PACKET.req must have a valid bulk data */
335 if ((bulkdata
->d
[0].data_length
== 0) || (bulkdata
->d
[0].os_data_ptr
== NULL
))
337 unifi_error(card
->ospriv
, "MA-PACKET.req with empty bulk data (%d bytes in %p)\n",
338 bulkdata
->d
[0].data_length
, bulkdata
->d
[0].os_data_ptr
);
339 dump((void *)sigptr
, siglen
);
340 return CSR_RESULT_FAILURE
;
343 /* Map the frame priority to a traffic queue index. */
344 frame_priority
= GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr
);
345 priority_q
= unifi_frame_priority_to_queue((CSR_PRIORITY
)frame_priority
);
347 sig_soft_q
= &card
->fh_traffic_queue
[priority_q
];
351 sig_soft_q
= &card
->fh_command_queue
;
354 r
= send_signal(card
, sigptr
, siglen
, bulkdata
, sig_soft_q
, priority_q
, run_bh
);
355 /* On error, the caller must free or requeue bulkdata buffers */
358 } /* unifi_send_signal() */
362 * ---------------------------------------------------------------------------
363 * unifi_send_resources_available
365 * Examines whether there is available space to queue
366 * a signal in the command or traffic queue
369 * card Pointer to card context struct
370 * sigptr Pointer to signal.
373 * CSR_RESULT_SUCCESS if resources available
374 * CSR_WIFI_HIP_RESULT_NO_SPACE if there was no free signal queue entry
377 * ---------------------------------------------------------------------------
379 CsrResult
unifi_send_resources_available(card_t
*card
, const u8
*sigptr
)
382 u16 signal_id
= GET_SIGNAL_ID(sigptr
);
385 * If the signal is a CSR_MA_PACKET_REQUEST ,
386 * we send it using the traffic soft queue. Else we use the command soft queue.
388 if (signal_id
== CSR_MA_PACKET_REQUEST_ID
)
393 /* Map the frame priority to a traffic queue index. */
394 frame_priority
= GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr
);
395 priority_q
= unifi_frame_priority_to_queue((CSR_PRIORITY
)frame_priority
);
397 sig_soft_q
= &card
->fh_traffic_queue
[priority_q
];
401 sig_soft_q
= &card
->fh_command_queue
;
404 /* Check that the fh_data_queue has a free slot */
405 if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sig_soft_q
))
407 unifi_notice(card
->ospriv
, "unifi_send_resources_available: %s full\n",
409 return CSR_WIFI_HIP_RESULT_NO_SPACE
;
412 return CSR_RESULT_SUCCESS
;
413 } /* unifi_send_resources_available() */