Merge branches 'delete-gts-bfs', 'misc', 'novell-bugzilla-757888-numa' and 'osc-pcie...
[cascardo/linux.git] / drivers / staging / csr / ul_int.c
1 /*
2  * ***************************************************************************
3  *  FILE:     ul_int.c
4  *
5  *  PURPOSE:
6  *      Manage list of client applications using UniFi.
7  *
8  * Copyright (C) 2006-2009 by Cambridge Silicon Radio Ltd.
9  *
10  * Refer to LICENSE.txt included with this source code for details on
11  * the license terms.
12  *
13  * ***************************************************************************
14  */
15 #include "csr_wifi_hip_unifi.h"
16 #include "csr_wifi_hip_conversions.h"
17 #include "unifi_priv.h"
18 #include "unifiio.h"
19 #include "unifi_os.h"
20
21 static void free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata);
22 static void reset_driver_status(unifi_priv_t *priv);
23
24 /*
25  * ---------------------------------------------------------------------------
26  *  ul_init_clients
27  *
28  *      Initialise the clients array to empty.
29  *
30  *  Arguments:
31  *      priv            Pointer to device private context struct
32  *
33  *  Returns:
34  *      None.
35  *
36  *  Notes:
37  *      This function needs to be called before priv is stored in
38  *      Unifi_instances[].
39  * ---------------------------------------------------------------------------
40  */
41 void
42 ul_init_clients(unifi_priv_t *priv)
43 {
44     int id;
45     ul_client_t *ul_clients;
46
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
48     sema_init(&priv->udi_logging_mutex, 1);
49 #else
50     init_MUTEX(&priv->udi_logging_mutex);
51 #endif
52     priv->logging_client = NULL;
53
54     ul_clients = priv->ul_clients;
55
56     for (id = 0; id < MAX_UDI_CLIENTS; id++) {
57         memset(&ul_clients[id], 0, sizeof(ul_client_t));
58
59         ul_clients[id].client_id = id;
60         ul_clients[id].sender_id = UDI_SENDER_ID_BASE + (id << UDI_SENDER_ID_SHIFT);
61         ul_clients[id].instance = -1;
62         ul_clients[id].event_hook = NULL;
63
64         INIT_LIST_HEAD(&ul_clients[id].udi_log);
65         init_waitqueue_head(&ul_clients[id].udi_wq);
66         sema_init(&ul_clients[id].udi_sem, 1);
67
68         ul_clients[id].wake_up_wq_id = 0;
69         ul_clients[id].seq_no = 0;
70         ul_clients[id].wake_seq_no = 0;
71         ul_clients[id].snap_filter.count = 0;
72     }
73 } /* ul_init_clients() */
74
75
76 /*
77  * ---------------------------------------------------------------------------
78  *  ul_register_client
79  *
80  *      This function registers a new ul client.
81  *
82  *  Arguments:
83  *      priv            Pointer to device private context struct
84  *      configuration   Special configuration for the client.
85  *      udi_event_clbk  Callback for receiving event from unifi.
86  *
87  *  Returns:
88  *      0 if a new clients is registered, -1 otherwise.
89  * ---------------------------------------------------------------------------
90  */
91 ul_client_t *
92 ul_register_client(unifi_priv_t *priv, unsigned int configuration,
93                    udi_event_t udi_event_clbk)
94 {
95     unsigned char id, ref;
96     ul_client_t *ul_clients;
97
98     ul_clients = priv->ul_clients;
99
100     /* check for an unused entry */
101     for (id = 0; id < MAX_UDI_CLIENTS; id++) {
102         if (ul_clients[id].udi_enabled == 0) {
103             ul_clients[id].instance = priv->instance;
104             ul_clients[id].udi_enabled = 1;
105             ul_clients[id].configuration = configuration;
106
107             /* Allocate memory for the reply signal.. */
108             ul_clients[id].reply_signal = kmalloc(sizeof(CSR_SIGNAL), GFP_KERNEL);
109             if (ul_clients[id].reply_signal == NULL) {
110                 unifi_error(priv, "Failed to allocate reply signal for client.\n");
111                 return NULL;
112             }
113             /* .. and the bulk data of the reply signal. */
114             for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
115                 ul_clients[id].reply_bulkdata[ref] = kmalloc(sizeof(bulk_data_t), GFP_KERNEL);
116                 /* If allocation fails, free allocated memory. */
117                 if (ul_clients[id].reply_bulkdata[ref] == NULL) {
118                     for (; ref > 0; ref --) {
119                         kfree(ul_clients[id].reply_bulkdata[ref - 1]);
120                     }
121                     kfree(ul_clients[id].reply_signal);
122                     unifi_error(priv, "Failed to allocate bulk data buffers for client.\n");
123                     return NULL;
124                 }
125             }
126
127             /* Set the event callback. */
128             ul_clients[id].event_hook = udi_event_clbk;
129
130             unifi_trace(priv, UDBG2, "UDI %d (0x%x) registered. configuration = 0x%x\n",
131                         id, &ul_clients[id], configuration);
132             return &ul_clients[id];
133         }
134     }
135     return NULL;
136 } /* ul_register_client() */
137
138
139 /*
140  * ---------------------------------------------------------------------------
141  *  ul_deregister_client
142  *
143  *      This function deregisters a blocking UDI client.
144  *
145  *  Arguments:
146  *      client      Pointer to the client we deregister.
147  *
148  *  Returns:
149  *      0 if a new clients is deregistered.
150  * ---------------------------------------------------------------------------
151  */
152 int
153 ul_deregister_client(ul_client_t *ul_client)
154 {
155     struct list_head *pos, *n;
156     udi_log_t *logptr;
157     unifi_priv_t *priv = uf_find_instance(ul_client->instance);
158     int ref;
159
160     ul_client->instance = -1;
161     ul_client->event_hook = NULL;
162     ul_client->udi_enabled = 0;
163     unifi_trace(priv, UDBG5, "UDI (0x%x) deregistered.\n", ul_client);
164
165     /* Free memory allocated for the reply signal and its bulk data. */
166     kfree(ul_client->reply_signal);
167     for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
168         kfree(ul_client->reply_bulkdata[ref]);
169     }
170
171     if (ul_client->snap_filter.count) {
172         ul_client->snap_filter.count = 0;
173         kfree(ul_client->snap_filter.protocols);
174     }
175
176     /* Free anything pending on the udi_log list */
177     down(&ul_client->udi_sem);
178     list_for_each_safe(pos, n, &ul_client->udi_log)
179     {
180         logptr = list_entry(pos, udi_log_t, q);
181         list_del(pos);
182         kfree(logptr);
183     }
184     up(&ul_client->udi_sem);
185
186     return 0;
187 } /* ul_deregister_client() */
188
189
190
191 /*
192  * ---------------------------------------------------------------------------
193  *  logging_handler
194  *
195  *      This function is registered with the driver core.
196  *      It is called every time a UniFi HIP Signal is sent. It iterates over
197  *      the list of processes interested in receiving log events and
198  *      delivers the events to them.
199  *
200  *  Arguments:
201  *      ospriv      Pointer to driver's private data.
202  *      sigdata     Pointer to the packed signal buffer.
203  *      signal_len  Length of the packed signal.
204  *      bulkdata    Pointer to the signal's bulk data.
205  *      dir         Direction of the signal
206  *                  0 = from-host
207  *                  1 = to-host
208  *
209  *  Returns:
210  *      None.
211  * ---------------------------------------------------------------------------
212  */
213 void
214 logging_handler(void *ospriv,
215                 u8 *sigdata, u32 signal_len,
216                 const bulk_data_param_t *bulkdata,
217                 enum udi_log_direction direction)
218 {
219     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
220     ul_client_t *client;
221     int dir;
222
223     dir = (direction == UDI_LOG_FROM_HOST) ? UDI_FROM_HOST : UDI_TO_HOST;
224
225     down(&priv->udi_logging_mutex);
226     client = priv->logging_client;
227     if (client != NULL) {
228         client->event_hook(client, sigdata, signal_len,
229                            bulkdata, dir);
230     }
231     up(&priv->udi_logging_mutex);
232
233 } /* logging_handler() */
234
235
236
237 /*
238  * ---------------------------------------------------------------------------
239  *  ul_log_config_ind
240  *
241  *      This function uses the client's register callback
242  *      to indicate configuration information e.g core errors.
243  *
244  *  Arguments:
245  *      priv        Pointer to driver's private data.
246  *      conf_param  Pointer to the configuration data.
247  *      len         Length of the configuration data.
248  *
249  *  Returns:
250  *      None.
251  * ---------------------------------------------------------------------------
252  */
253 void
254 ul_log_config_ind(unifi_priv_t *priv, u8 *conf_param, int len)
255 {
256 #ifdef CSR_SUPPORT_SME
257     if (priv->smepriv == NULL)
258     {
259         return;
260     }
261     if ((CONFIG_IND_ERROR == (*conf_param)) && (priv->wifi_on_state == wifi_on_in_progress)) {
262         unifi_notice(priv, "ul_log_config_ind: wifi on in progress, suppress error\n");
263     } else {
264         /* wifi_off_ind (error or exit) */
265         CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, (CsrWifiRouterCtrlControlIndication)(*conf_param));
266     }
267 #ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
268     unifi_debug_buf_dump();
269 #endif
270 #else
271     bulk_data_param_t bulkdata;
272
273     /*
274      * If someone killed unifi_managed before the driver was unloaded
275      * the g_drvpriv pointer is going to be NULL. In this case it is
276      * safe to assume that there is no client to get the indication.
277      */
278     if (!priv) {
279         unifi_notice(NULL, "uf_sme_event_ind: NULL priv\n");
280         return;
281     }
282
283     /* Create a null bulkdata structure. */
284     bulkdata.d[0].data_length = 0;
285     bulkdata.d[1].data_length = 0;
286
287     sme_native_log_event(priv->sme_cli, conf_param, sizeof(u8),
288                          &bulkdata, UDI_CONFIG_IND);
289
290 #endif /* CSR_SUPPORT_SME */
291
292 } /* ul_log_config_ind */
293
294
295 /*
296  * ---------------------------------------------------------------------------
297  *  free_bulkdata_buffers
298  *
299  *      Free the bulkdata buffers e.g. after a failed unifi_send_signal().
300  *
301  *  Arguments:
302  *      priv        Pointer to device private struct
303  *      bulkdata    Pointer to bulkdata parameter table
304  *
305  *  Returns:
306  *      None.
307  * ---------------------------------------------------------------------------
308  */
309 static void
310 free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata)
311 {
312     int i;
313
314     if (bulkdata) {
315         for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i) {
316             if (bulkdata->d[i].data_length != 0) {
317                 unifi_net_data_free(priv, (bulk_data_desc_t *)(&bulkdata->d[i]));
318                 /* data_length is now 0 */
319             }
320         }
321     }
322
323 } /* free_bulkdata_buffers */
324
325 static int
326 _align_bulk_data_buffers(unifi_priv_t *priv, u8 *signal,
327                          bulk_data_param_t *bulkdata)
328 {
329     unsigned int i;
330
331     if ((bulkdata == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
332         return 0;
333     }
334
335     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
336     {
337         struct sk_buff *skb;
338         /*
339         * The following complex casting is in place in order to eliminate 64-bit compilation warning
340         * "cast to/from pointer from/to integer of different size"
341         */
342         u32 align_offset = (u32)(long)(bulkdata->d[i].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1);
343         if (align_offset)
344         {
345             skb = (struct sk_buff*)bulkdata->d[i].os_net_buf_ptr;
346             if (skb == NULL) {
347                 unifi_warning(priv,
348                               "_align_bulk_data_buffers: Align offset found (%d) but skb is NULL!\n",
349                               align_offset);
350                 return -EINVAL;
351             }
352             if (bulkdata->d[i].data_length == 0) {
353                 unifi_warning(priv,
354                               "_align_bulk_data_buffers: Align offset found (%d) but length is zero\n",
355                               align_offset);
356                 return CSR_RESULT_SUCCESS;
357             }
358             unifi_trace(priv, UDBG5,
359                         "Align f-h buffer (0x%p) by %d bytes (skb->data: 0x%p)\n",
360                         bulkdata->d[i].os_data_ptr, align_offset, skb->data);
361
362
363             /* Check if there is enough headroom... */
364             if (unlikely(skb_headroom(skb) < align_offset))
365             {
366                 struct sk_buff *tmp = skb;
367
368                 unifi_trace(priv, UDBG5, "Headroom not enough - realloc it\n");
369                 skb = skb_realloc_headroom(skb, align_offset);
370                 if (skb == NULL) {
371                     unifi_error(priv,
372                                 "_align_bulk_data_buffers: skb_realloc_headroom failed - signal is dropped\n");
373                     return -EFAULT;
374                 }
375                 /* Free the old bulk data only if allocation succeeds */
376                 kfree_skb(tmp);
377                 /* Bulkdata needs to point to the new skb */
378                 bulkdata->d[i].os_net_buf_ptr = (const unsigned char*)skb;
379                 bulkdata->d[i].os_data_ptr = (const void*)skb->data;
380             }
381             /* ... before pushing the data to the right alignment offset */
382             skb_push(skb, align_offset);
383
384         }
385         /* The direction bit is zero for the from-host */
386         signal[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1] = align_offset;
387
388     }
389     return 0;
390 } /* _align_bulk_data_buffers() */
391
392
393 /*
394  * ---------------------------------------------------------------------------
395  *  ul_send_signal_unpacked
396  *
397  *      This function sends a host formatted signal to unifi.
398  *
399  *  Arguments:
400  *      priv        Pointer to driver's private data.
401  *      sigptr      Pointer to the signal.
402  *      bulkdata    Pointer to the signal's bulk data.
403  *
404  *  Returns:
405  *      O on success, error code otherwise.
406  *
407  *  Notes:
408  *  The signals have to be sent in the format described in the host interface
409  *  specification, i.e wire formatted. Certain clients use the host formatted
410  *  structures. The write_pack() transforms the host formatted signal
411  *  into the wired formatted signal. The code is in the core, since the signals
412  *  are defined therefore binded to the host interface specification.
413  * ---------------------------------------------------------------------------
414  */
415 int
416 ul_send_signal_unpacked(unifi_priv_t *priv, CSR_SIGNAL *sigptr,
417                         bulk_data_param_t *bulkdata)
418 {
419     u8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
420     u16 packed_siglen;
421     CsrResult csrResult;
422     unsigned long lock_flags;
423     int r;
424
425
426     csrResult = write_pack(sigptr, sigbuf, &packed_siglen);
427     if (csrResult != CSR_RESULT_SUCCESS) {
428         unifi_error(priv, "Malformed HIP signal in ul_send_signal_unpacked()\n");
429         return CsrHipResultToStatus(csrResult);
430     }
431     r = _align_bulk_data_buffers(priv, sigbuf, (bulk_data_param_t*)bulkdata);
432     if (r) {
433         return r;
434     }
435
436     spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
437     csrResult = unifi_send_signal(priv->card, sigbuf, packed_siglen, bulkdata);
438     if (csrResult != CSR_RESULT_SUCCESS) {
439   /*      free_bulkdata_buffers(priv, (bulk_data_param_t *)bulkdata); */
440         spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
441         return CsrHipResultToStatus(csrResult);
442     }
443     spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
444
445     return 0;
446 } /* ul_send_signal_unpacked() */
447
448
449 /*
450  * ---------------------------------------------------------------------------
451  *  reset_driver_status
452  *
453  *      This function is called from ul_send_signal_raw() when it detects
454  *      that the SME has sent a MLME-RESET request.
455  *
456  *  Arguments:
457  *      priv        Pointer to device private struct
458  *
459  *  Returns:
460  *      None.
461  * ---------------------------------------------------------------------------
462  */
463 static void
464 reset_driver_status(unifi_priv_t *priv)
465 {
466     priv->sta_wmm_capabilities = 0;
467 #ifdef CSR_NATIVE_LINUX
468 #ifdef CSR_SUPPORT_WEXT
469     priv->wext_conf.flag_associated = 0;
470     priv->wext_conf.block_controlled_port = CSR_WIFI_ROUTER_PORT_ACTION_8021X_PORT_OPEN;
471     priv->wext_conf.bss_wmm_capabilities = 0;
472     priv->wext_conf.disable_join_on_ssid_set = 0;
473 #endif
474 #endif
475 } /* reset_driver_status() */
476
477
478 /*
479  * ---------------------------------------------------------------------------
480  *  ul_send_signal_raw
481  *
482  *      This function sends a wire formatted data signal to unifi.
483  *
484  *  Arguments:
485  *      priv        Pointer to driver's private data.
486  *      sigptr      Pointer to the signal.
487  *      siglen      Length of the signal.
488  *      bulkdata    Pointer to the signal's bulk data.
489  *
490  *  Returns:
491  *      O on success, error code otherwise.
492  * ---------------------------------------------------------------------------
493  */
494 int
495 ul_send_signal_raw(unifi_priv_t *priv, unsigned char *sigptr, int siglen,
496                    bulk_data_param_t *bulkdata)
497 {
498     CsrResult csrResult;
499     unsigned long lock_flags;
500     int r;
501
502     /*
503      * Make sure that the signal is updated with the bulk data
504      * alignment for DMA.
505      */
506     r = _align_bulk_data_buffers(priv, (u8*)sigptr, bulkdata);
507     if (r) {
508         return r;
509     }
510
511     spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
512     csrResult = unifi_send_signal(priv->card, sigptr, siglen, bulkdata);
513     if (csrResult != CSR_RESULT_SUCCESS) {
514         free_bulkdata_buffers(priv, bulkdata);
515         spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
516         return CsrHipResultToStatus(csrResult);
517     }
518     spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
519
520     /*
521      * Since this is use by unicli, if we get an MLME reset request
522      * we need to initialize a few status parameters
523      * that the driver uses to make decisions.
524      */
525     if (GET_SIGNAL_ID(sigptr) == CSR_MLME_RESET_REQUEST_ID) {
526         reset_driver_status(priv);
527     }
528
529     return 0;
530 } /* ul_send_signal_raw() */
531
532