summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/wil6210/wmi.c
diff options
context:
space:
mode:
authorLior David <liord@codeaurora.org>2018-02-26 21:12:14 +0300
committerKalle Valo <kvalo@codeaurora.org>2018-02-27 19:50:26 +0300
commit4aebd3bdbd8a26ebcd2398289e2379472d17825f (patch)
treea6558e4cbca2ed12b8a21718e56ddbbab2a4478e /drivers/net/wireless/ath/wil6210/wmi.c
parente00243fab84b4efd5a250d1c47a4ddcca4c666ce (diff)
downloadlinux-4aebd3bdbd8a26ebcd2398289e2379472d17825f.tar.xz
wil6210: add support for adding and removing virtual interfaces
Add generic support in cfg80211 operations add_virtual_intf and del_virtual_intf for adding/removing VIFs of any interface type, and fix change_virtual_intf to allow changing the interface type of a VIF. Previously these operations only worked for the P2P_DEVICE interface which is not a real VIF(it is management-only and shares radio with the main interface). Currently the interface combination is validated, the VIF is added/removed in the firmware and the appropriate net/wireless device is also added/removed. Added minimal support for proper interface up/down and module unload but most operations still work only on the main interface. Signed-off-by: Lior David <liord@codeaurora.org> Signed-off-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/wmi.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c111
1 files changed, 107 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 044d69850353..23c28bf07f28 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -656,11 +656,14 @@ static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
struct wiphy *wiphy = wil_to_wiphy(wil);
struct wmi_ready_event *evt = d;
- wil->n_mids = evt->numof_additional_mids;
-
wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
wil->fw_version, le32_to_cpu(evt->sw_version),
- evt->mac, wil->n_mids);
+ evt->mac, evt->numof_additional_mids);
+ if (evt->numof_additional_mids + 1 < wil->max_vifs) {
+ wil_err(wil, "FW does not support enough MIDs (need %d)",
+ wil->max_vifs - 1);
+ return; /* FW load will fail after timeout */
+ }
/* ignore MAC address, we already have it from the boot loader */
strlcpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version));
@@ -2372,6 +2375,92 @@ int wmi_resume(struct wil6210_priv *wil)
return reply.evt.status;
}
+int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
+ const u8 *mac, enum nl80211_iftype iftype)
+{
+ int rc;
+ struct wmi_port_allocate_cmd cmd = {
+ .mid = mid,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_port_allocated_event evt;
+ } __packed reply;
+
+ wil_dbg_misc(wil, "port allocate, mid %d iftype %d, mac %pM\n",
+ mid, iftype, mac);
+
+ ether_addr_copy(cmd.mac, mac);
+ switch (iftype) {
+ case NL80211_IFTYPE_STATION:
+ cmd.port_role = WMI_PORT_STA;
+ break;
+ case NL80211_IFTYPE_AP:
+ cmd.port_role = WMI_PORT_AP;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ cmd.port_role = WMI_PORT_P2P_CLIENT;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ cmd.port_role = WMI_PORT_P2P_GO;
+ break;
+ /* what about monitor??? */
+ default:
+ wil_err(wil, "unsupported iftype: %d\n", iftype);
+ return -EINVAL;
+ }
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_PORT_ALLOCATE_CMDID, mid,
+ &cmd, sizeof(cmd),
+ WMI_PORT_ALLOCATED_EVENTID, &reply,
+ sizeof(reply), 300);
+ if (rc) {
+ wil_err(wil, "failed to allocate port, status %d\n", rc);
+ return rc;
+ }
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "WMI_PORT_ALLOCATE returned status %d\n",
+ reply.evt.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wmi_port_delete(struct wil6210_priv *wil, u8 mid)
+{
+ int rc;
+ struct wmi_port_delete_cmd cmd = {
+ .mid = mid,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_port_deleted_event evt;
+ } __packed reply;
+
+ wil_dbg_misc(wil, "port delete, mid %d\n", mid);
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_PORT_DELETE_CMDID, mid,
+ &cmd, sizeof(cmd),
+ WMI_PORT_DELETED_EVENTID, &reply,
+ sizeof(reply), 2000);
+ if (rc) {
+ wil_err(wil, "failed to delete port, status %d\n", rc);
+ return rc;
+ }
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "WMI_PORT_DELETE returned status %d\n",
+ reply.evt.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static bool wmi_evt_call_handler(struct wil6210_vif *vif, int id,
void *d, int len)
{
@@ -2391,7 +2480,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
struct wil6210_mbox_hdr *hdr)
{
u16 len = le16_to_cpu(hdr->len);
- struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
+ struct wil6210_vif *vif;
if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
(len >= sizeof(struct wmi_cmd_hdr))) {
@@ -2404,6 +2493,20 @@ static void wmi_event_handle(struct wil6210_priv *wil,
eventid2name(id), id, wil->reply_id,
wil->reply_mid);
+ if (mid == MID_BROADCAST)
+ mid = 0;
+ if (mid >= wil->max_vifs) {
+ wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
+ mid);
+ return;
+ }
+ vif = wil->vifs[mid];
+ if (!vif) {
+ wil_dbg_wmi(wil, "event for empty VIF(%d), skipped\n",
+ mid);
+ return;
+ }
+
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id &&
wil->reply_mid == mid) {