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>
This commit is contained in:
Vladimir Kondratiev 2014-02-27 16:20:40 +02:00 committed by John W. Linville
parent c98db0bec7
commit 1647f12f1b
3 changed files with 105 additions and 0 deletions

View File

@ -352,6 +352,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return rc;
}
static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie)
{
const u8 *buf = params->buf;
size_t len = params->len;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
struct wmi_sw_tx_req_cmd *cmd;
struct {
struct wil6210_mbox_hdr_wmi wmi;
struct wmi_sw_tx_complete_event evt;
} __packed evt;
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!cmd)
return -ENOMEM;
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
cmd->len = cpu_to_le16(len);
memcpy(cmd->payload, buf, len);
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (rc == 0)
rc = evt.evt.status;
kfree(cmd);
return rc;
}
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
@ -402,6 +436,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
return 0;
}
static int wil_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
unsigned int duration,
u64 *cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
/* TODO: handle duration */
wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
rc = wmi_set_channel(wil, chan->hw_value);
if (rc)
return rc;
rc = wmi_rxon(wil, true);
return rc;
}
static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
wil_info(wil, "%s()\n", __func__);
rc = wmi_rxon(wil, false);
return rc;
}
static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon)
{
@ -510,6 +579,9 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.disconnect = wil_cfg80211_disconnect,
.change_virtual_intf = wil_cfg80211_change_iface,
.get_station = wil_cfg80211_get_station,
.remain_on_channel = wil_remain_on_channel,
.cancel_remain_on_channel = wil_cancel_remain_on_channel,
.mgmt_tx = wil_cfg80211_mgmt_tx,
.set_monitor_channel = wil_cfg80211_set_channel,
.add_key = wil_cfg80211_add_key,
.del_key = wil_cfg80211_del_key,

View File

@ -357,6 +357,7 @@ int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);

View File

@ -893,6 +893,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
return rc;
}
/**
* wmi_rxon - turn radio on/off
* @on: turn on if true, off otherwise
*
* Only switch radio. Channel should be set separately.
* No timeout for rxon - radio turned on forever unless some other call
* turns it off
*/
int wmi_rxon(struct wil6210_priv *wil, bool on)
{
int rc;
struct {
struct wil6210_mbox_hdr_wmi wmi;
struct wmi_listen_started_event evt;
} __packed reply;
wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
if (on) {
rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
WMI_LISTEN_STARTED_EVENTID,
&reply, sizeof(reply), 100);
if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
rc = -EINVAL;
} else {
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
}
return rc;
}
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
{
struct wireless_dev *wdev = wil->wdev;