Merge tag 'cpumask-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty...
[cascardo/linux.git] / drivers / staging / csr / sme_native.c
1 /*
2  * ***************************************************************************
3  *
4  *  FILE:     sme_native.c
5  *
6  * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
7  *
8  * Refer to LICENSE.txt included with this source code for details on
9  * the license terms.
10  *
11  * ***************************************************************************
12  */
13
14 #include <linux/netdevice.h>
15
16 #include "unifi_priv.h"
17 #include "csr_wifi_hip_unifi.h"
18 #include "csr_wifi_hip_conversions.h"
19
20 static const unsigned char wildcard_address[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
21
22 int
23 uf_sme_init(unifi_priv_t *priv)
24 {
25     func_enter();
26
27 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
28     sema_init(&priv->mlme_blocking_mutex, 1);
29 #else
30     init_MUTEX(&priv->mlme_blocking_mutex);
31 #endif
32
33 #ifdef CSR_SUPPORT_WEXT
34     {
35         int r = uf_init_wext_interface(priv);
36         if (r != 0) {
37             func_exit();
38             return r;
39         }
40     }
41 #endif
42
43
44
45     func_exit();
46     return 0;
47 } /* uf_sme_init() */
48
49
50 void
51 uf_sme_deinit(unifi_priv_t *priv)
52 {
53
54     func_enter();
55
56     /* Free memory allocated for the scan table */
57 /*    unifi_clear_scan_table(priv); */
58
59     /* Cancel any pending workqueue tasks */
60     flush_workqueue(priv->unifi_workqueue);
61
62 #ifdef CSR_SUPPORT_WEXT
63     uf_deinit_wext_interface(priv);
64 #endif
65
66
67     func_exit();
68 } /* uf_sme_deinit() */
69
70
71 int sme_mgt_wifi_on(unifi_priv_t *priv)
72 {
73     int r,i;
74     s32 csrResult;
75
76     if (priv == NULL) {
77         return -EINVAL;
78     }
79     /* Initialize the interface mode to None */
80     for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
81         priv->interfacePriv[i]->interfaceMode = 0;
82     }
83
84     /* Set up interface mode so that get_packet_priority() can
85      * select the right QOS priority when WMM is enabled.
86      */
87     priv->interfacePriv[0]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_STA;
88
89     r = uf_request_firmware_files(priv, UNIFI_FW_STA);
90     if (r) {
91         unifi_error(priv, "sme_mgt_wifi_on: Failed to get f/w\n");
92         return r;
93     }
94
95     /*
96      * The request to initialise UniFi might come while UniFi is running.
97      * We need to block all I/O activity until the reset completes, otherwise
98      * an SDIO error might occur resulting an indication to the SME which
99      * makes it think that the initialisation has failed.
100      */
101     priv->bh_thread.block_thread = 1;
102
103     /* Power on UniFi */
104     CsrSdioClaim(priv->sdio);
105     csrResult = CsrSdioPowerOn(priv->sdio);
106     CsrSdioRelease(priv->sdio);
107     if(csrResult != CSR_RESULT_SUCCESS && csrResult != CSR_SDIO_RESULT_NOT_RESET) {
108         return -EIO;
109     }
110
111     if (csrResult == CSR_RESULT_SUCCESS) {
112         /* Initialise UniFi hardware */
113         r = uf_init_hw(priv);
114         if (r) {
115             return r;
116         }
117     }
118
119     /* Re-enable the I/O thread */
120     priv->bh_thread.block_thread = 0;
121
122     /* Disable deep sleep signalling during the firmware initialisation, to
123      * prevent the wakeup mechanism raising the SDIO clock beyond INIT before
124      * the first MLME-RESET.ind. It gets re-enabled at the CONNECTED.ind,
125      * immediately after the MLME-RESET.ind
126      */
127     csrResult = unifi_configure_low_power_mode(priv->card,
128                                            UNIFI_LOW_POWER_DISABLED,
129                                            UNIFI_PERIODIC_WAKE_HOST_DISABLED);
130     if (csrResult != CSR_RESULT_SUCCESS) {
131         unifi_warning(priv,
132                       "sme_mgt_wifi_on: unifi_configure_low_power_mode() returned an error\n");
133     }
134
135
136     /* Start the I/O thread */
137     CsrSdioClaim(priv->sdio);
138     r = uf_init_bh(priv);
139     if (r) {
140         CsrSdioPowerOff(priv->sdio);
141         CsrSdioRelease(priv->sdio);
142         return r;
143     }
144     CsrSdioRelease(priv->sdio);
145
146     priv->init_progress = UNIFI_INIT_FW_DOWNLOADED;
147
148     return 0;
149 }
150
151 int
152 sme_sys_suspend(unifi_priv_t *priv)
153 {
154     const int interfaceNum = 0;     /* FIXME */
155     CsrResult csrResult;
156
157     /* Abort any pending requests. */
158     uf_abort_mlme(priv);
159
160     /* Allow our mlme request to go through. */
161     priv->io_aborted = 0;
162
163     /* Send MLME-RESET.req to UniFi. */
164     unifi_reset_state(priv, priv->netdev[interfaceNum]->dev_addr, 0);
165
166     /* Stop the network traffic */
167     netif_carrier_off(priv->netdev[interfaceNum]);
168
169     /* Put UniFi to deep sleep */
170     CsrSdioClaim(priv->sdio);
171     csrResult = unifi_force_low_power_mode(priv->card);
172     CsrSdioRelease(priv->sdio);
173
174     return 0;
175 } /* sme_sys_suspend() */
176
177
178 int
179 sme_sys_resume(unifi_priv_t *priv)
180 {
181 #ifdef CSR_SUPPORT_WEXT
182     /* Send disconnect event so clients will re-initialise connection. */
183     memset(priv->wext_conf.current_ssid, 0, UNIFI_MAX_SSID_LEN);
184     memset((void*)priv->wext_conf.current_bssid, 0, ETH_ALEN);
185     priv->wext_conf.capability = 0;
186     wext_send_disassoc_event(priv);
187 #endif
188     return 0;
189 } /* sme_sys_resume() */
190
191
192 /*
193  * ---------------------------------------------------------------------------
194  *  sme_native_log_event
195  *
196  *      Callback function to be registered as the SME event callback.
197  *      Copies the signal content into a new udi_log_t struct and adds
198  *      it to the read queue for the SME client.
199  *
200  *  Arguments:
201  *      arg             This is the value given to unifi_add_udi_hook, in
202  *                      this case a pointer to the client instance.
203  *      signal          Pointer to the received signal.
204  *      signal_len      Size of the signal structure in bytes.
205  *      bulkdata        Pointers to any associated bulk data.
206  *      dir             Direction of the signal. Zero means from host,
207  *                      non-zero means to host.
208  *
209  *  Returns:
210  *      None.
211  * ---------------------------------------------------------------------------
212  */
213 void
214 sme_native_log_event(ul_client_t *pcli,
215                      const u8 *sig_packed, int sig_len,
216                      const bulk_data_param_t *bulkdata,
217                      int dir)
218 {
219     unifi_priv_t *priv;
220     udi_log_t *logptr;
221     u8 *p;
222     int i, r;
223     int signal_len;
224     int total_len;
225     udi_msg_t *msgptr;
226     CSR_SIGNAL signal;
227     ul_client_t *client = pcli;
228
229     func_enter();
230
231     if (client == NULL) {
232         unifi_error(NULL, "sme_native_log_event: client has exited\n");
233         return;
234     }
235
236     priv = uf_find_instance(client->instance);
237     if (!priv) {
238         unifi_error(priv, "invalid priv\n");
239         return;
240     }
241
242     /* Just a sanity check */
243     if ((sig_packed == NULL) || (sig_len <= 0)) {
244         return;
245     }
246
247     /* Get the unpacked signal */
248     r = read_unpack_signal(sig_packed, &signal);
249     if (r == 0) {
250         signal_len = SigGetSize(&signal);
251     } else {
252         u16 receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sig_packed) + sizeof(u16)) & 0xFF00;
253
254         /* The control indications are 1 byte, pass them to client. */
255         if (sig_len == 1) {
256             unifi_trace(priv, UDBG5,
257                         "Control indication (0x%x) for native SME.\n",
258                         *sig_packed);
259
260             *(u8*)&signal = *sig_packed;
261             signal_len = sig_len;
262         } else if (receiver_id == 0) {
263             /*
264              * Also "unknown" signals with a ReceiverId of 0 are passed to the client
265              * without unpacking. (This is a code size optimisation to allow signals
266              * that the driver not interested in to be dropped from the unpack code).
267              */
268             unifi_trace(priv, UDBG5,
269                         "Signal 0x%.4X with ReceiverId 0 for native SME.\n",
270                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
271
272             *(u8*)&signal = *sig_packed;
273             signal_len = sig_len;
274         } else {
275             unifi_error(priv,
276                         "sme_native_log_event - Received unknown signal 0x%.4X.\n",
277                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
278             return;
279         }
280     }
281
282     unifi_trace(priv, UDBG3, "sme_native_log_event: signal 0x%.4X for %d\n",
283                 signal.SignalPrimitiveHeader.SignalId,
284                 client->client_id);
285
286     total_len = signal_len;
287     /* Calculate the buffer we need to store signal plus bulk data */
288     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
289         total_len += bulkdata->d[i].data_length;
290     }
291
292     /* Allocate log structure plus actual signal. */
293     logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
294
295     if (logptr == NULL) {
296         unifi_error(priv,
297                     "Failed to allocate %d bytes for a UDI log record\n",
298                     sizeof(udi_log_t) + total_len);
299         return;
300     }
301
302     /* Fill in udi_log struct */
303     INIT_LIST_HEAD(&logptr->q);
304     msgptr = &logptr->msg;
305     msgptr->length = sizeof(udi_msg_t) + total_len;
306     msgptr->timestamp = jiffies_to_msecs(jiffies);
307     msgptr->direction = dir;
308     msgptr->signal_length = signal_len;
309
310     /* Copy signal and bulk data to the log */
311     p = (u8 *)(msgptr + 1);
312     memcpy(p, &signal, signal_len);
313     p += signal_len;
314
315     /* Append any bulk data */
316     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
317         int len = bulkdata->d[i].data_length;
318
319         /*
320          * Len here might not be the same as the length in the bulk data slot.
321          * The slot length will always be even, but len could be odd.
322          */
323         if (len > 0) {
324             if (bulkdata->d[i].os_data_ptr) {
325                 memcpy(p, bulkdata->d[i].os_data_ptr, len);
326             } else {
327                 memset(p, 0, len);
328             }
329             p += len;
330         }
331     }
332
333     /* Add to tail of log queue */
334     down(&client->udi_sem);
335     list_add_tail(&logptr->q, &client->udi_log);
336     up(&client->udi_sem);
337
338     /* Wake any waiting user process */
339     wake_up_interruptible(&client->udi_wq);
340
341     func_exit();
342
343 } /* sme_native_log_event() */
344
345
346 /*
347  * ---------------------------------------------------------------------------
348  *  unifi_ta_indicate_protocol
349  *
350  *      Report that a packet of a particular type has been seen
351  *
352  *  Arguments:
353  *      drv_priv        The device context pointer passed to ta_init.
354  *      protocol        The protocol type enum value.
355  *      direction       Whether the packet was a tx or rx.
356  *      src_addr        The source MAC address from the data packet.
357  *
358  *  Returns:
359  *      None.
360  *
361  *  Notes:
362  *      We defer the actual sending to a background workqueue,
363  *      see uf_ta_ind_wq().
364  * ---------------------------------------------------------------------------
365  */
366 void
367 unifi_ta_indicate_protocol(void *ospriv,
368                            CsrWifiRouterCtrlTrafficPacketType packet_type,
369                            CsrWifiRouterCtrlProtocolDirection direction,
370                            const CsrWifiMacAddress *src_addr)
371 {
372
373 } /* unifi_ta_indicate_protocol */
374
375 /*
376  * ---------------------------------------------------------------------------
377  * unifi_ta_indicate_sampling
378  *
379  *      Send the TA sampling information to the SME.
380  *
381  *  Arguments:
382  *      drv_priv        The device context pointer passed to ta_init.
383  *      stats           The TA sampling data to send.
384  *
385  *  Returns:
386  *      None.
387  * ---------------------------------------------------------------------------
388  */
389 void
390 unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
391 {
392
393 } /* unifi_ta_indicate_sampling() */
394
395
396 void
397 unifi_ta_indicate_l4stats(void *ospriv,
398                             u32 rxTcpThroughput,
399                             u32 txTcpThroughput,
400                             u32 rxUdpThroughput,
401                             u32 txUdpThroughput)
402 {
403
404 } /* unifi_ta_indicate_l4stats() */
405
406 /*
407  * ---------------------------------------------------------------------------
408  * uf_native_process_udi_signal
409  *
410  *      Process interesting signals from the UDI interface.
411  *
412  *  Arguments:
413  *      pcli            A pointer to the client instance.
414  *      signal          Pointer to the received signal.
415  *      signal_len      Size of the signal structure in bytes.
416  *      bulkdata        Pointers to any associated bulk data.
417  *      dir             Direction of the signal. Zero means from host,
418  *                      non-zero means to host.
419  *
420  *
421  *  Returns:
422  *      None.
423  * ---------------------------------------------------------------------------
424  */
425 void
426 uf_native_process_udi_signal(ul_client_t *pcli,
427                              const u8 *packed_signal, int packed_signal_len,
428                              const bulk_data_param_t *bulkdata, int dir)
429 {
430
431 } /* uf_native_process_udi_signal() */
432
433
434 /*
435  * ---------------------------------------------------------------------------
436  *  sme_native_mlme_event_handler
437  *
438  *      Callback function to be used as the udi_event_callback when registering
439  *      as a client.
440  *      This function implements a blocking request-reply interface for WEXT.
441  *      To use it, a client specifies this function as the udi_event_callback
442  *      to ul_register_client(). The signal dispatcher in
443  *      unifi_receive_event() will call this function to deliver a signal.
444  *
445  *  Arguments:
446  *      pcli            Pointer to the client instance.
447  *      signal          Pointer to the received signal.
448  *      signal_len      Size of the signal structure in bytes.
449  *      bulkdata        Pointer to structure containing any associated bulk data.
450  *      dir             Direction of the signal. Zero means from host,
451  *                      non-zero means to host.
452  *
453  *  Returns:
454  *      None.
455  * ---------------------------------------------------------------------------
456  */
457 void
458 sme_native_mlme_event_handler(ul_client_t *pcli,
459                               const u8 *sig_packed, int sig_len,
460                               const bulk_data_param_t *bulkdata,
461                               int dir)
462 {
463     CSR_SIGNAL signal;
464     int signal_len;
465     unifi_priv_t *priv = uf_find_instance(pcli->instance);
466     int id, r;
467
468     func_enter();
469
470     /* Just a sanity check */
471     if ((sig_packed == NULL) || (sig_len <= 0)) {
472         return;
473     }
474
475     /* Get the unpacked signal */
476     r = read_unpack_signal(sig_packed, &signal);
477     if (r == 0) {
478         signal_len = SigGetSize(&signal);
479     } else {
480         unifi_error(priv,
481                     "sme_native_mlme_event_handler - Received unknown signal 0x%.4X.\n",
482                     CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
483         return;
484     }
485
486     id = signal.SignalPrimitiveHeader.SignalId;
487     unifi_trace(priv, UDBG4, "wext - Process signal 0x%.4X\n", id);
488
489     /*
490      * Take the appropriate action for the signal.
491      */
492     switch (id) {
493         /*
494          * Confirm replies from UniFi.
495          * These all have zero or one CSR_DATAREF member. (FIXME: check this is still true for softmac)
496          */
497         case CSR_MA_PACKET_CONFIRM_ID:
498         case CSR_MLME_RESET_CONFIRM_ID:
499         case CSR_MLME_GET_CONFIRM_ID:
500         case CSR_MLME_SET_CONFIRM_ID:
501         case CSR_MLME_GET_NEXT_CONFIRM_ID:
502         case CSR_MLME_POWERMGT_CONFIRM_ID:
503         case CSR_MLME_SCAN_CONFIRM_ID:
504         case CSR_MLME_HL_SYNC_CONFIRM_ID:
505         case CSR_MLME_MEASURE_CONFIRM_ID:
506         case CSR_MLME_SETKEYS_CONFIRM_ID:
507         case CSR_MLME_DELETEKEYS_CONFIRM_ID:
508         case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
509         case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
510         case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
511         case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
512         case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
513         case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
514         case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
515         case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
516         case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
517         case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
518         case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
519         case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
520         case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
521         case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
522         case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
523         case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
524         case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
525         case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
526         case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
527         case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
528         case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
529         case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
530         case CSR_MLME_SM_START_CONFIRM_ID:
531         case CSR_MLME_LEAVE_CONFIRM_ID:
532         case CSR_MLME_SET_TIM_CONFIRM_ID:
533         case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
534         case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
535         case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
536         case CSR_DEBUG_GENERIC_CONFIRM_ID:
537             unifi_mlme_copy_reply_and_wakeup_client(pcli, &signal, signal_len, bulkdata);
538             break;
539
540         case CSR_MLME_CONNECTED_INDICATION_ID:
541             /* We currently ignore the connected-ind for softmac f/w development */
542             unifi_info(priv, "CSR_MLME_CONNECTED_INDICATION_ID ignored\n");
543             break;
544
545         default:
546             break;
547     }
548
549     func_exit();
550 } /* sme_native_mlme_event_handler() */
551
552
553
554 /*
555  * -------------------------------------------------------------------------
556  *  unifi_reset_state
557  *
558  *      Ensure that a MAC address has been set.
559  *      Send the MLME-RESET signal.
560  *      This must be called at least once before starting to do any
561  *      network activities (e.g. scan, join etc).
562  *
563  * Arguments:
564  *      priv            Pointer to device private context struct
565  *      macaddr         Pointer to chip MAC address.
566  *                      If this is FF:FF:FF:FF:FF:FF it will be replaced
567  *                      with the MAC address from the chip.
568  *      set_default_mib 1 if the f/w must reset the MIB to the default values
569  *                      0 otherwise
570  *
571  * Returns:
572  *      0 on success, an error code otherwise.
573  * -------------------------------------------------------------------------
574  */
575 int
576 unifi_reset_state(unifi_priv_t *priv, unsigned char *macaddr,
577                   unsigned char set_default_mib)
578 {
579     int r = 0;
580
581     func_enter();
582
583 #ifdef CSR_SUPPORT_WEXT
584     /* The reset clears any 802.11 association. */
585     priv->wext_conf.flag_associated = 0;
586 #endif
587
588     func_exit();
589     return r;
590 } /* unifi_reset_state() */
591