diff options
author | Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | 2014-02-27 09:20:40 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-28 14:33:27 -0500 |
commit | 1647f12f1b511c2629b9b8d23061aa54ad8a9795 (patch) | |
tree | 07753b3fa605dd542f6081c3f558f9bc5d5fcca2 /drivers | |
parent | c98db0bec72ac7ef127119c1ed962d6f56802b12 (diff) |
wil6210: Tx management frame
Implement management frame passing. In order to receive frame on the other
side, remain_on_channel() should be implemented as well
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/cfg80211.c | 72 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 32 |
3 files changed, 105 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5b340769d5bb..204c7c82b1b5 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -352,6 +352,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, | |||
352 | return rc; | 352 | return rc; |
353 | } | 353 | } |
354 | 354 | ||
355 | static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, | ||
356 | struct wireless_dev *wdev, | ||
357 | struct cfg80211_mgmt_tx_params *params, | ||
358 | u64 *cookie) | ||
359 | { | ||
360 | const u8 *buf = params->buf; | ||
361 | size_t len = params->len; | ||
362 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
363 | int rc; | ||
364 | struct ieee80211_mgmt *mgmt_frame = (void *)buf; | ||
365 | struct wmi_sw_tx_req_cmd *cmd; | ||
366 | struct { | ||
367 | struct wil6210_mbox_hdr_wmi wmi; | ||
368 | struct wmi_sw_tx_complete_event evt; | ||
369 | } __packed evt; | ||
370 | |||
371 | cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); | ||
372 | if (!cmd) | ||
373 | return -ENOMEM; | ||
374 | |||
375 | memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); | ||
376 | cmd->len = cpu_to_le16(len); | ||
377 | memcpy(cmd->payload, buf, len); | ||
378 | |||
379 | rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, | ||
380 | WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); | ||
381 | if (rc == 0) | ||
382 | rc = evt.evt.status; | ||
383 | |||
384 | kfree(cmd); | ||
385 | |||
386 | return rc; | ||
387 | } | ||
388 | |||
355 | static int wil_cfg80211_set_channel(struct wiphy *wiphy, | 389 | static int wil_cfg80211_set_channel(struct wiphy *wiphy, |
356 | struct cfg80211_chan_def *chandef) | 390 | struct cfg80211_chan_def *chandef) |
357 | { | 391 | { |
@@ -402,6 +436,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, | |||
402 | return 0; | 436 | return 0; |
403 | } | 437 | } |
404 | 438 | ||
439 | static int wil_remain_on_channel(struct wiphy *wiphy, | ||
440 | struct wireless_dev *wdev, | ||
441 | struct ieee80211_channel *chan, | ||
442 | unsigned int duration, | ||
443 | u64 *cookie) | ||
444 | { | ||
445 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
446 | int rc; | ||
447 | |||
448 | /* TODO: handle duration */ | ||
449 | wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); | ||
450 | |||
451 | rc = wmi_set_channel(wil, chan->hw_value); | ||
452 | if (rc) | ||
453 | return rc; | ||
454 | |||
455 | rc = wmi_rxon(wil, true); | ||
456 | |||
457 | return rc; | ||
458 | } | ||
459 | |||
460 | static int wil_cancel_remain_on_channel(struct wiphy *wiphy, | ||
461 | struct wireless_dev *wdev, | ||
462 | u64 cookie) | ||
463 | { | ||
464 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
465 | int rc; | ||
466 | |||
467 | wil_info(wil, "%s()\n", __func__); | ||
468 | |||
469 | rc = wmi_rxon(wil, false); | ||
470 | |||
471 | return rc; | ||
472 | } | ||
473 | |||
405 | static int wil_fix_bcon(struct wil6210_priv *wil, | 474 | static int wil_fix_bcon(struct wil6210_priv *wil, |
406 | struct cfg80211_beacon_data *bcon) | 475 | struct cfg80211_beacon_data *bcon) |
407 | { | 476 | { |
@@ -510,6 +579,9 @@ static struct cfg80211_ops wil_cfg80211_ops = { | |||
510 | .disconnect = wil_cfg80211_disconnect, | 579 | .disconnect = wil_cfg80211_disconnect, |
511 | .change_virtual_intf = wil_cfg80211_change_iface, | 580 | .change_virtual_intf = wil_cfg80211_change_iface, |
512 | .get_station = wil_cfg80211_get_station, | 581 | .get_station = wil_cfg80211_get_station, |
582 | .remain_on_channel = wil_remain_on_channel, | ||
583 | .cancel_remain_on_channel = wil_cancel_remain_on_channel, | ||
584 | .mgmt_tx = wil_cfg80211_mgmt_tx, | ||
513 | .set_monitor_channel = wil_cfg80211_set_channel, | 585 | .set_monitor_channel = wil_cfg80211_set_channel, |
514 | .add_key = wil_cfg80211_add_key, | 586 | .add_key = wil_cfg80211_add_key, |
515 | .del_key = wil_cfg80211_del_key, | 587 | .del_key = wil_cfg80211_del_key, |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1f91eaf95bbe..0d7fba4f09e2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -357,6 +357,7 @@ int wmi_echo(struct wil6210_priv *wil); | |||
357 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); | 357 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); |
358 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); | 358 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); |
359 | int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); | 359 | int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); |
360 | int wmi_rxon(struct wil6210_priv *wil, bool on); | ||
360 | int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); | 361 | int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); |
361 | 362 | ||
362 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); | 363 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); |
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422a..d65da5590c5f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -893,6 +893,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | |||
893 | return rc; | 893 | return rc; |
894 | } | 894 | } |
895 | 895 | ||
896 | /** | ||
897 | * wmi_rxon - turn radio on/off | ||
898 | * @on: turn on if true, off otherwise | ||
899 | * | ||
900 | * Only switch radio. Channel should be set separately. | ||
901 | * No timeout for rxon - radio turned on forever unless some other call | ||
902 | * turns it off | ||
903 | */ | ||
904 | int wmi_rxon(struct wil6210_priv *wil, bool on) | ||
905 | { | ||
906 | int rc; | ||
907 | struct { | ||
908 | struct wil6210_mbox_hdr_wmi wmi; | ||
909 | struct wmi_listen_started_event evt; | ||
910 | } __packed reply; | ||
911 | |||
912 | wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); | ||
913 | |||
914 | if (on) { | ||
915 | rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, | ||
916 | WMI_LISTEN_STARTED_EVENTID, | ||
917 | &reply, sizeof(reply), 100); | ||
918 | if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) | ||
919 | rc = -EINVAL; | ||
920 | } else { | ||
921 | rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, | ||
922 | WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); | ||
923 | } | ||
924 | |||
925 | return rc; | ||
926 | } | ||
927 | |||
896 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | 928 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) |
897 | { | 929 | { |
898 | struct wireless_dev *wdev = wil->wdev; | 930 | struct wireless_dev *wdev = wil->wdev; |