Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d90f7b37 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: multiple VIFs support for connections and data path" into msm-4.14

parents 7f2eed2d 168168f2
Loading
Loading
Loading
Loading
+15 −17
Original line number Diff line number Diff line
@@ -391,7 +391,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
	sinfo->tx_packets = stats->tx_packets;
	sinfo->tx_failed = stats->tx_errors;

	if (test_bit(wil_status_fwconnected, wil->status)) {
	if (test_bit(wil_vif_fwconnected, vif->status)) {
		sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
		if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
			     wil->fw_capabilities))
@@ -562,11 +562,10 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
			return ERR_PTR(-EINVAL);
		}

		vif = kzalloc(sizeof(*vif), GFP_KERNEL);
		if (!vif)
		p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
		if (!p2p_wdev)
			return ERR_PTR(-ENOMEM);

		p2p_wdev = vif_to_wdev(vif);
		p2p_wdev->iftype = type;
		p2p_wdev->wiphy = wiphy;
		/* use our primary ethernet address */
@@ -976,8 +975,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_print_connect_params(wil, sme);

	if (test_bit(wil_status_fwconnecting, wil->status) ||
	    test_bit(wil_status_fwconnected, wil->status))
	if (test_bit(wil_vif_fwconnecting, vif->status) ||
	    test_bit(wil_vif_fwconnected, vif->status))
		return -EALREADY;

	if (sme->ie_len > WMI_MAX_IE_LEN) {
@@ -1081,18 +1080,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	ether_addr_copy(conn.bssid, bss->bssid);
	ether_addr_copy(conn.dst_mac, bss->bssid);

	set_bit(wil_status_fwconnecting, wil->status);
	set_bit(wil_vif_fwconnecting, vif->status);

	rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn));
	if (rc == 0) {
		netif_carrier_on(ndev);
		if (!wil_has_other_active_ifaces(wil, ndev, false, true))
			wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
		vif->bss = bss;
		/* Connect can take lots of time */
		mod_timer(&vif->connect_timer,
			  jiffies + msecs_to_jiffies(5000));
	} else {
		clear_bit(wil_status_fwconnecting, wil->status);
		clear_bit(wil_vif_fwconnecting, vif->status);
	}

 out:
@@ -1112,8 +1112,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
	wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n",
		     reason_code, vif->mid);

	if (!(test_bit(wil_status_fwconnecting, wil->status) ||
	      test_bit(wil_status_fwconnected, wil->status))) {
	if (!(test_bit(wil_vif_fwconnecting, vif->status) ||
	      test_bit(wil_vif_fwconnected, vif->status))) {
		wil_err(wil, "Disconnect was called while disconnected\n");
		return 0;
	}
@@ -2017,7 +2017,7 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
	mutex_lock(&wil->mutex);
	mutex_lock(&wil->vif_mutex);
	wil_p2p_stop_radio_operations(wil);
	wil_abort_scan(ndev_to_vif(wil->main_ndev), true);
	wil_abort_scan_all_vifs(wil, true);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->mutex);

@@ -2312,7 +2312,6 @@ void wil_cfg80211_deinit(struct wil6210_priv *wil)
void wil_p2p_wdev_free(struct wil6210_priv *wil)
{
	struct wireless_dev *p2p_wdev;
	struct wil6210_vif *vif;

	mutex_lock(&wil->vif_mutex);
	p2p_wdev = wil->p2p_wdev;
@@ -2321,8 +2320,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
	mutex_unlock(&wil->vif_mutex);
	if (p2p_wdev) {
		cfg80211_unregister_wdev(p2p_wdev);
		vif = wdev_to_vif(wil, p2p_wdev);
		kfree(vif);
		kfree(p2p_wdev);
	}
}

@@ -2616,7 +2614,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
			return -ENOENT;
		}
	} else {
		if (test_bit(wil_status_fwconnected, wil->status)) {
		if (test_bit(wil_vif_fwconnected, vif->status)) {
			wil_err(wil, "must specify MAC address when connected\n");
			return -EINVAL;
		}
@@ -2743,7 +2741,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
			cid = -1;
		}
	} else {
		if (test_bit(wil_status_fwconnected, wil->status)) {
		if (test_bit(wil_vif_fwconnected, vif->status)) {
			wil_err(wil, "must specify MAC address when connected\n");
			return -EINVAL;
		}
+16 −4
Original line number Diff line number Diff line
@@ -1246,12 +1246,13 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	struct station_info sinfo;
	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
	int i, rc;

	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		struct wil_sta_info *p = &wil->sta[i];
		char *status = "unknown";
		struct wil6210_vif *vif;
		u8 mid;

		switch (p->status) {
		case wil_sta_unused:
@@ -1264,9 +1265,15 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			status = "connected";
			break;
		}
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d][MID %d] %pM %s\n",
			   i, mid, p->addr, status);

		if (p->status == wil_sta_connected) {
		if (p->status != wil_sta_connected)
			continue;

		vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
		if (vif) {
			rc = wil_cid_fill_sinfo(vif, i, &sinfo);
			if (rc)
				return rc;
@@ -1274,6 +1281,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			seq_printf(s, "  Tx_mcs = %d\n", sinfo.txrate.mcs);
			seq_printf(s, "  Rx_mcs = %d\n", sinfo.rxrate.mcs);
			seq_printf(s, "  SQ     = %d\n", sinfo.signal);
		} else {
			seq_puts(s, "  INVALID MID\n");
		}
	}

@@ -1465,6 +1474,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
		struct wil_sta_info *p = &wil->sta[i];
		char *status = "unknown";
		u8 aid = 0;
		u8 mid;

		switch (p->status) {
		case wil_sta_unused:
@@ -1478,7 +1488,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			aid = p->aid;
			break;
		}
		seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
			   mid, aid);

		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)

void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{
	bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status);
	bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;

	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
	      unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
+55 −23
Original line number Diff line number Diff line
@@ -175,6 +175,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
		     cid, sta->mid, sta->status);
	/* inform upper/lower layers */
	if (sta->status != wil_sta_unused) {
		if (vif->mid != sta->mid) {
			wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
				vif->mid);
			/* let FW override sta->mid but be more strict with
			 * user space requests
			 */
			if (!from_event)
				return;
		}
		if (!from_event) {
			bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
						disable_ap_sme : false;
@@ -278,32 +287,35 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_bcast_fini(vif);
		wil_update_net_queues_bh(wil, NULL, true);
		wil_update_net_queues_bh(wil, vif, NULL, true);
		netif_carrier_off(ndev);
		if (!wil_has_other_active_ifaces(wil, ndev, false, true))
			wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);

		if (test_bit(wil_status_fwconnected, wil->status)) {
			clear_bit(wil_status_fwconnected, wil->status);
		if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
			atomic_dec(&wil->connected_vifs);
			cfg80211_disconnected(ndev, reason_code,
					      NULL, 0,
					      vif->locally_generated_disc,
					      GFP_KERNEL);
			vif->locally_generated_disc = false;
		} else if (test_bit(wil_status_fwconnecting, wil->status)) {
		} else if (test_bit(wil_vif_fwconnecting, vif->status)) {
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
			vif->bss = NULL;
		}
		clear_bit(wil_status_fwconnecting, wil->status);
		clear_bit(wil_vif_fwconnecting, vif->status);
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
		if (!wil_vif_is_connected(wil, vif->mid)) {
			wil_update_net_queues_bh(wil, NULL, true);
			clear_bit(wil_status_fwconnected, wil->status);
			wil_update_net_queues_bh(wil, vif, NULL, true);
			if (test_and_clear_bit(wil_vif_fwconnected,
					       vif->status))
				atomic_dec(&wil->connected_vifs);
		} else {
			wil_update_net_queues_bh(wil, NULL, false);
			wil_update_net_queues_bh(wil, vif, NULL, false);
		}
		break;
	default:
@@ -323,11 +335,11 @@ void wil_disconnect_worker(struct work_struct *work)
		struct wmi_disconnect_event evt;
	} __packed reply;

	if (test_bit(wil_status_fwconnected, wil->status))
	if (test_bit(wil_vif_fwconnected, vif->status))
		/* connect succeeded after all */
		return;

	if (!test_bit(wil_status_fwconnecting, wil->status))
	if (!test_bit(wil_vif_fwconnecting, vif->status))
		/* already disconnected */
		return;

@@ -339,11 +351,11 @@ void wil_disconnect_worker(struct work_struct *work)
		return;
	}

	wil_update_net_queues_bh(wil, NULL, true);
	wil_update_net_queues_bh(wil, vif, NULL, true);
	netif_carrier_off(ndev);
	cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
				WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
	clear_bit(wil_status_fwconnecting, wil->status);
	clear_bit(wil_vif_fwconnecting, vif->status);
}

static int wil_wait_for_recovery(struct wil6210_priv *wil)
@@ -1096,6 +1108,20 @@ void wil_abort_scan(struct wil6210_vif *vif, bool sync)
	}
}

void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
{
	int i;

	lockdep_assert_held(&wil->vif_mutex);

	for (i = 0; i < wil->max_vifs; i++) {
		struct wil6210_vif *vif = wil->vifs[i];

		if (vif)
			wil_abort_scan(vif, sync);
	}
}

int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
{
	int rc;
@@ -1148,6 +1174,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
		vif = wil->vifs[i];
		if (!vif)
			continue;
		vif->ap_isolate = 0;
		if (vif->mid) {
			ndev = vif_to_ndev(vif);
			wdev = vif_to_wdev(vif);
@@ -1171,10 +1198,10 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
 */
int wil_reset(struct wil6210_priv *wil, bool load_fw)
{
	int rc;
	int rc, i;
	unsigned long status_flags = BIT(wil_status_resetting);
	int no_flash;
	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
	struct wil6210_vif *vif;

	wil_dbg_misc(wil, "reset\n");

@@ -1226,17 +1253,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
		goto out;
	}

	mutex_lock(&wil->vif_mutex);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);

	for (i = 0; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (vif) {
			cancel_work_sync(&vif->disconnect_worker);
	wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
			wil6210_disconnect(vif, NULL,
					   WLAN_REASON_DEAUTH_LEAVING, false);
		}
	}
	wil_bcast_fini_all(wil);

	/* Disable device led before reset*/
	wmi_led_cfg(wil, false);

	mutex_lock(&wil->vif_mutex);
	wil_abort_scan(vif, false);
	mutex_unlock(&wil->vif_mutex);

	/* prevent NAPI from being scheduled and prevent wmi commands */
	mutex_lock(&wil->wmi_mutex);
	if (test_bit(wil_status_suspending, wil->status))
@@ -1306,7 +1339,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
	}

	/* init after reset */
	vif->ap_isolate = 0;
	reinit_completion(&wil->wmi_ready);
	reinit_completion(&wil->wmi_call);
	reinit_completion(&wil->halp.comp);
@@ -1467,7 +1499,7 @@ int __wil_down(struct wil6210_priv *wil)

	mutex_lock(&wil->vif_mutex);
	wil_p2p_stop_radio_operations(wil);
	wil_abort_scan(ndev_to_vif(wil->main_ndev), false);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);

	return wil_reset(wil, false);
+42 −5
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil,

bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
{
	/* use NULL ndev argument to check all interfaces */
	return wil_has_other_active_ifaces(wil, NULL, up, ok);
}

@@ -143,11 +144,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
		struct vring *vring = &wil->vring_tx[i];
		struct vring_tx_data *txdata = &wil->vring_tx_data[i];
		struct wil6210_vif *vif;

		if (!vring->va || !txdata->enabled ||
		    txdata->mid >= wil->max_vifs)
			continue;

		if (!vring->va || !txdata->enabled)
		vif = wil->vifs[txdata->mid];
		if (unlikely(!vif)) {
			wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid);
			continue;
		}

		tx_done += wil_tx_complete(wil, i);
		tx_done += wil_tx_complete(vif, i);
	}

	if (tx_done < budget) {
@@ -246,7 +255,10 @@ static void wil_vif_init(struct wil6210_vif *vif)
	INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);

	INIT_LIST_HEAD(&vif->probe_client_pending);

	wil_ftm_init(vif);

	vif->net_queue_stopped = 1;
}

static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
@@ -422,12 +434,14 @@ int wil_if_add(struct wil6210_priv *wil)
		return rc;
	}

	netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
	init_dummy_netdev(&wil->napi_ndev);
	netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
		       WIL6210_NAPI_BUDGET);
	netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
	netif_tx_napi_add(&wil->napi_ndev,
			  &wil->napi_tx, wil6210_netdev_poll_tx,
			  WIL6210_NAPI_BUDGET);

	wil_update_net_queues_bh(wil, NULL, true);
	wil_update_net_queues_bh(wil, vif, NULL, true);

	rtnl_lock();
	rc = wil_vif_add(wil, vif);
@@ -466,10 +480,29 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
	 */
	unregister_netdevice(ndev);

	mutex_lock(&wil->mutex);
	wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
	mutex_unlock(&wil->mutex);

	if (any_active && vif->mid != 0)
		wmi_port_delete(wil, vif->mid);

	/* make sure no one is accessing the VIF before removing */
	mutex_lock(&wil->vif_mutex);
	wil->vifs[mid] = NULL;
	/* ensure NAPI code will see the NULL VIF */
	wmb();
	if (test_bit(wil_status_napi_en, wil->status)) {
		napi_synchronize(&wil->napi_rx);
		napi_synchronize(&wil->napi_tx);
	}
	mutex_unlock(&wil->vif_mutex);

	flush_work(&wil->wmi_event_worker);
	del_timer_sync(&vif->connect_timer);
	cancel_work_sync(&vif->disconnect_worker);
	wil_probe_client_flush(vif);
	cancel_work_sync(&vif->probe_client_worker);
	/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
	 * the main interface will be freed in wil_if_free, we need to keep it
	 * a bit longer so logging macros will work.
@@ -486,5 +519,9 @@ void wil_if_remove(struct wil6210_priv *wil)
	rtnl_lock();
	wil_vif_remove(wil, 0);
	rtnl_unlock();

	netif_napi_del(&wil->napi_tx);
	netif_napi_del(&wil->napi_rx);

	wiphy_unregister(wdev->wiphy);
}
Loading