Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 0/3] brcmfmac: sdio: Deal better w/ transmission errors waking from sleep
From: Arend Van Spriel @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Douglas Anderson, Ulf Hansson, Kalle Valo, Adrian Hunter
  Cc: linux-rockchip, Double Lo, briannorris, Madhan Mohan R, mka,
	Wright Feng, Chi-Hsien Lin, linux-mmc, Shawn Lin,
	brcm80211-dev-list, YueHaibing, Hante Meuleman, Martin Hicks,
	Ritesh Harjani, Michael Trimarchi, Wolfram Sang, Franky Lin,
	Jiong Wu, brcm80211-dev-list.pdl, David S. Miller, netdev,
	linux-wireless, linux-kernel, Naveen Gupta, Avri Altman
In-Reply-To: <20190517225420.176893-1-dianders@chromium.org>

On 5/18/2019 12:54 AM, Douglas Anderson wrote:
> This series attempts to deal better with the expected transmission
> errors that we get when waking up the SDIO-based WiFi on
> rk3288-veyron-minnie, rk3288-veyron-speedy, and rk3288-veyron-mickey.
> 
> Some details about those errors can be found in
> <https://crbug.com/960222>, but to summarize it here: if we try to
> send the wakeup command to the WiFi card at the same time it has
> decided to wake up itself then it will behave badly on the SDIO bus.
> This can cause timeouts or CRC errors.
> 
> When I tested on 4.19 and 4.20 these CRC errors can be seen to cause
> re-tuning.  Since I am currently developing on 4.19 this was the
> original problem I attempted to solve.
> 
> On mainline it turns out that you don't see the retuning errors but
> you see tons of spam about timeouts trying to wakeup from sleep.  I
> tracked down the commit that was causing that and have partially
> reverted it here.  I have no real knowledge about Broadcom WiFi, but
> the commit that was causing problems sounds (from the descriptioin) to
> be a hack commit penalizing all Broadcom WiFi users because of a bug
> in a Cypress SD controller.  I will let others comment if this is
> truly the case and, if so, what the right solution should be.

Let me give a bit of background. The brcmfmac driver implements its own 
runtime-pm like functionality, ie. if the driver is idle for some time 
it will put the device in a low-power state. When it does that it powers 
down several cores in the chip among which the SDIO core. However, the 
SDIO bus used be very bad at handling devices that do that so instead it 
has the Always-On-Station (AOS) block take over the SDIO core in 
handling the bus. Default is will send a R1 response, but only for CMD52 
(and CMD14 but no host is using that cruft). In noCmdDecode it does not 
respond and simply wakes up the SDIO core, which takes over again. 
Because it does not respond timeouts (-110) are kinda expected in this mode.

Regards,
Arend

^ permalink raw reply

* [PATCH V5 6/8] ath11k: add defines for max MCS rates per phymode
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/core.h  | 4 ++++
 drivers/net/wireless/ath/ath11k/dp_rx.c | 4 ++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index a7c59ea0c228..d0d960b384e7 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -46,6 +46,10 @@ enum wme_ac {
 	WME_NUM_AC
 };
 
+#define ATH11K_HT_MCS_MAX	7
+#define ATH11K_VHT_MCS_MAX	9
+#define ATH11K_HE_MCS_MAX	11
+
 static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
 {
 	return (((tid == 0) || (tid == 3)) ? WME_AC_BE :
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 62820c20f7c1..e52a54cd2b79 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1705,7 +1705,7 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, void *rx_desc,
 		break;
 	case RX_MSDU_START_PKT_TYPE_11N:
 		rx_status->encoding = RX_ENC_HT;
-		if (rate_mcs > 7) {
+		if (rate_mcs > ATH11K_HT_MCS_MAX) {
 			ath11k_warn(ar->ab, "Received with invalid mcs in HT mode %d\n", rate_mcs);
 			break;
 		}
@@ -1717,7 +1717,7 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, void *rx_desc,
 	case RX_MSDU_START_PKT_TYPE_11AC:
 		rx_status->encoding = RX_ENC_VHT;
 		rx_status->rate_idx = rate_mcs;
-		if (rate_mcs > 9) {
+		if (rate_mcs > ATH11K_VHT_MCS_MAX) {
 			ath11k_warn(ar->ab, "Received with invalid mcs in VHT mode %d\n", rate_mcs);
 			break;
 		}
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 0/8] ath11k: add HE support
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin

This series adds initial support for HE mode to the ath11k driver.

Things that still need to implemented
* ppe_threshold support

Changes in V2:
* generate sband_iftype data from FW provided capabilities
* properly handle rx_status for HE frames
* fix regression in basic VHF phymode
* various minor cleanups

Changes in V3
* make the he_cap generating code future-proof
* move phymode lookup to an array

Changes in V4
* remove dependency in local patch

Changes in V5
* populate he_oper field when preparing peer assoc
* populate ppet field when preparing peer assoc
* fix 80p80 phymode when preparing peer assoc
* address review comments

John Crispin (8):
  mac80211: propagate HE operation info into ieee80211_sta
  ath11k: fix some whitespace errors
  ath11k: move phymode selection from function to array lookup
  ath11k: add HE handling to the debug code
  ath11k: extend reading of FW capabilities
  ath11k: add defines for max MCS rates per phymode
  ath11k: handle rx status for HE frames
  ath11k: add HE support

 drivers/net/wireless/ath/ath11k/core.h        |  11 +-
 drivers/net/wireless/ath/ath11k/debugfs_sta.c |  24 +-
 drivers/net/wireless/ath/ath11k/dp_rx.c       |  18 +-
 drivers/net/wireless/ath/ath11k/mac.c         | 357 ++++++++++++++----
 drivers/net/wireless/ath/ath11k/reg.c         |   1 +
 drivers/net/wireless/ath/ath11k/wmi.c         |  13 +-
 drivers/net/wireless/ath/ath11k/wmi.h         |  44 ++-
 include/net/mac80211.h                        |   2 +
 include/uapi/linux/nl80211.h                  |   4 +
 net/mac80211/he.c                             |  14 +
 net/mac80211/ieee80211_i.h                    |   5 +
 net/mac80211/mlme.c                           |   1 +
 12 files changed, 392 insertions(+), 102 deletions(-)

-- 
2.20.1


^ permalink raw reply

* [PATCH V5 2/8] ath11k: fix some whitespace errors
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/wmi.h | 38 +++++++++++++--------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 366a136e53ac..0fa33f38abdf 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -4139,28 +4139,28 @@ struct wmi_unit_test_cmd {
 
 #define MAX_SUPPORTED_RATES 128
 
-#define WMI_PEER_AUTH           0x00000001
-#define WMI_PEER_QOS            0x00000002
-#define WMI_PEER_NEED_PTK_4_WAY 0x00000004
-#define WMI_PEER_NEED_GTK_2_WAY 0x00000010
-#define WMI_PEER_HE             0x00000400
-#define WMI_PEER_APSD           0x00000800
-#define WMI_PEER_HT             0x00001000
-#define WMI_PEER_40MHZ          0x00002000
-#define WMI_PEER_STBC           0x00008000
-#define WMI_PEER_LDPC           0x00010000
-#define WMI_PEER_DYN_MIMOPS     0x00020000
-#define WMI_PEER_STATIC_MIMOPS  0x00040000
-#define WMI_PEER_SPATIAL_MUX    0x00200000
-#define WMI_PEER_VHT            0x02000000
-#define WMI_PEER_80MHZ          0x04000000
-#define WMI_PEER_PMF            0x08000000
+#define WMI_PEER_AUTH		0x00000001
+#define WMI_PEER_QOS		0x00000002
+#define WMI_PEER_NEED_PTK_4_WAY	0x00000004
+#define WMI_PEER_NEED_GTK_2_WAY	0x00000010
+#define WMI_PEER_HE		0x00000400
+#define WMI_PEER_APSD		0x00000800
+#define WMI_PEER_HT		0x00001000
+#define WMI_PEER_40MHZ		0x00002000
+#define WMI_PEER_STBC		0x00008000
+#define WMI_PEER_LDPC		0x00010000
+#define WMI_PEER_DYN_MIMOPS	0x00020000
+#define WMI_PEER_STATIC_MIMOPS	0x00040000
+#define WMI_PEER_SPATIAL_MUX	0x00200000
+#define WMI_PEER_VHT		0x02000000
+#define WMI_PEER_80MHZ		0x04000000
+#define WMI_PEER_PMF		0x08000000
 /* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000.
  * Need to be cleaned up
  */
-#define WMI_PEER_IS_P2P_CAPABLE 0x20000000
-#define WMI_PEER_160MHZ         0x40000000
-#define WMI_PEER_SAFEMODE_EN    0x80000000
+#define WMI_PEER_IS_P2P_CAPABLE	0x20000000
+#define WMI_PEER_160MHZ		0x40000000
+#define WMI_PEER_SAFEMODE_EN	0x80000000
 
 struct beacon_tmpl_params {
 	u8 vdev_id;
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 8/8] ath11k: add HE support
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

Add basic HE support to the driver. The sband_iftype data is generated from
the capabilities read from the FW.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/core.h |   2 +
 drivers/net/wireless/ath/ath11k/mac.c  | 240 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath11k/reg.c  |   1 +
 drivers/net/wireless/ath/ath11k/wmi.c  |   6 +-
 drivers/net/wireless/ath/ath11k/wmi.h  |   6 +-
 5 files changed, 245 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index d0d960b384e7..54b136a4d6e9 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -443,6 +443,8 @@ struct ath11k {
 
 	struct {
 		struct ieee80211_supported_band sbands[NUM_NL80211_BANDS];
+		struct ieee80211_sband_iftype_data
+			iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
 	} mac;
 	unsigned long dev_flags;
 	unsigned int filter_flags;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index c5a55fb893ae..b436e90f627a 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1281,7 +1281,75 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
 				   struct ieee80211_sta *sta,
 				   struct peer_assoc_params *arg)
 {
-	/* TODO: Implementation */
+	const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+
+	if (!he_cap->has_he)
+		return;
+
+	arg->he_flag = true;
+
+	memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
+	       sizeof(arg->peer_he_cap_macinfo));
+	memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
+	       sizeof(arg->peer_he_cap_phyinfo));
+	memcpy(&arg->peer_he_ops, &sta->he_operation, sizeof(arg->peer_he_ops));
+
+	if (he_cap->he_cap_elem.phy_cap_info[6] &
+	    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
+		int bit = 7;
+		int nss, ru;
+
+		arg->peer_ppet.numss_m1 = he_cap->ppe_thres[0] &
+					  IEEE80211_PPE_THRES_NSS_MASK;
+		arg->peer_ppet.ru_bit_mask =
+			(he_cap->ppe_thres[0] &
+			 IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >>
+			IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS;
+
+		for (nss = 0; nss <= arg->peer_ppet.numss_m1; nss++) {
+			for (ru = 0; ru < 4; ru++) {
+				u32 val = 0;
+				int i;
+
+				if ((arg->peer_ppet.ru_bit_mask & BIT(ru)) == 0)
+					continue;
+				for (i = 0; i < 6; i++) {
+					val >>= 1;
+					val |= ((he_cap->ppe_thres[bit / 8] >>
+						 (bit % 8)) & 0x1) << 5;
+					bit++;
+				}
+				arg->peer_ppet.ppet16_ppet8_ru3_ru0[nss] |=
+								val << (ru * 6);
+			}
+		}
+	}
+
+	switch (sta->bandwidth) {
+	case IEEE80211_STA_RX_BW_160:
+		if (he_cap->he_cap_elem.phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
+			arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] =
+				he_cap->he_mcs_nss_supp.rx_mcs_80p80;
+			arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] =
+				he_cap->he_mcs_nss_supp.tx_mcs_80p80;
+			arg->peer_he_mcs_count++;
+		}
+		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] =
+			he_cap->he_mcs_nss_supp.rx_mcs_160;
+		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] =
+			he_cap->he_mcs_nss_supp.tx_mcs_160;
+		arg->peer_he_mcs_count++;
+		/* drop through */
+
+	default:
+		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] =
+			he_cap->he_mcs_nss_supp.rx_mcs_80;
+		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] =
+			he_cap->he_mcs_nss_supp.tx_mcs_80;
+		arg->peer_he_mcs_count++;
+		break;
+	}
 }
 
 static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta,
@@ -1448,6 +1516,32 @@ static enum wmi_phy_mode ath11k_mac_get_phymode_vht(struct ath11k *ar,
 	return MODE_UNKNOWN;
 }
 
+static enum wmi_phy_mode ath11k_mac_get_phymode_he(struct ath11k *ar,
+						   struct ieee80211_sta *sta)
+{
+	if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
+		if (sta->he_cap.he_cap_elem.phy_cap_info[0] &
+		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+			return MODE_11AX_HE160;
+		else if (sta->he_cap.he_cap_elem.phy_cap_info[0] &
+		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+			return MODE_11AX_HE80_80;
+		/* not sure if this is a valid case? */
+		return MODE_11AX_HE160;
+	}
+
+	if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
+		return MODE_11AX_HE80;
+
+	if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+		return MODE_11AX_HE40;
+
+	if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
+		return MODE_11AX_HE20;
+
+	return MODE_UNKNOWN;
+}
+
 static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 					struct ieee80211_vif *vif,
 					struct ieee80211_sta *sta,
@@ -1469,7 +1563,14 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 
 	switch (band) {
 	case NL80211_BAND_2GHZ:
-		if (sta->vht_cap.vht_supported &&
+		if (sta->he_cap.has_he) {
+			if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
+				phymode = MODE_11AX_HE80_2G;
+			else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+				phymode = MODE_11AX_HE40_2G;
+			else
+				phymode = MODE_11AX_HE20_2G;
+		} else if (sta->vht_cap.vht_supported &&
 		    !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
 			if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
 				phymode = MODE_11AC_VHT40;
@@ -1486,12 +1587,12 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 		} else {
 			phymode = MODE_11B;
 		}
-		/* TODO: HE */
-
 		break;
 	case NL80211_BAND_5GHZ:
-		/* Check VHT first */
-		if (sta->vht_cap.vht_supported &&
+		/* Check HE first */
+		if (sta->he_cap.has_he) {
+			phymode = ath11k_mac_get_phymode_he(ar, sta);
+		} else if (sta->vht_cap.vht_supported &&
 		    !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
 			phymode = ath11k_mac_get_phymode_vht(ar, sta);
 		} else if (sta->ht_cap.ht_supported &&
@@ -1503,7 +1604,6 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 		} else {
 			phymode = MODE_11A;
 		}
-		/* TODO: HE Phymode */
 		break;
 	default:
 		break;
@@ -3077,6 +3177,128 @@ static int ath11k_check_chain_mask(struct ath11k *ar, u32 ant, bool is_tx_ant)
 	return 0;
 }
 
+static void ath11k_gen_ppe_thresh(struct ath11k_ppe_threshold *fw_ppet,
+				  u8 *he_ppet)
+{
+	int nss, ru;
+	u8 bit = 7;
+
+	he_ppet[0] = fw_ppet->numss_m1 & IEEE80211_PPE_THRES_NSS_MASK;
+	he_ppet[0] |= (fw_ppet->ru_bit_mask <<
+		       IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) &
+		      IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK;
+	for (nss = 0; nss <= fw_ppet->numss_m1; nss++) {
+		for (ru = 0; ru < 4; ru++) {
+			u8 val;
+			int i;
+
+			if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0)
+				continue;
+			val = (fw_ppet->ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) &
+			       0x3f;
+			val = ((val >> 3) & 0x7) | ((val & 0x7) << 3);
+			for (i = 5; i >= 0; i--) {
+				he_ppet[bit / 8] |=
+					((val >> i) & 0x1) << ((bit % 8));
+				bit++;
+			}
+		}
+	}
+}
+
+static int ath11k_mac_copy_he_cap(struct ath11k_pdev_cap *cap,
+				  struct ieee80211_sband_iftype_data *data,
+				  int band)
+{
+	int i, idx = 0;
+
+	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
+		struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
+		struct ath11k_band_cap *band_cap = &cap->band[band];
+		struct ieee80211_he_cap_elem *he_cap_elem =
+				&he_cap->he_cap_elem;
+
+		switch (i) {
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_AP:
+			break;
+
+		default:
+			continue;
+		}
+
+		data[idx].types_mask = BIT(i);
+		he_cap->has_he = true;
+		memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info,
+		       sizeof(he_cap_elem->mac_cap_info));
+		memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info,
+		       sizeof(he_cap_elem->phy_cap_info));
+
+		he_cap_elem->mac_cap_info[1] |=
+			IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
+		switch (i) {
+		case NL80211_IFTYPE_AP:
+			he_cap_elem->phy_cap_info[9] |=
+				IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
+			break;
+		case NL80211_IFTYPE_STATION:
+			he_cap_elem->mac_cap_info[0] &=
+				~IEEE80211_HE_MAC_CAP0_TWT_RES;
+			he_cap_elem->mac_cap_info[0] |=
+				IEEE80211_HE_MAC_CAP0_TWT_REQ;
+			he_cap_elem->phy_cap_info[9] |=
+				IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
+			break;
+		}
+
+		he_cap->he_mcs_nss_supp.rx_mcs_80 =
+			cpu_to_le16(band_cap->he_mcs & 0xffff);
+		he_cap->he_mcs_nss_supp.tx_mcs_80 =
+			cpu_to_le16(band_cap->he_mcs & 0xffff);
+		he_cap->he_mcs_nss_supp.rx_mcs_160 =
+			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+		he_cap->he_mcs_nss_supp.tx_mcs_160 =
+			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+		he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
+			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+		he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
+			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+
+		memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
+		if (he_cap_elem->phy_cap_info[6] &
+		    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
+			ath11k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres);
+		idx++;
+	}
+
+	return idx;
+}
+
+static void ath11k_mac_setup_he_cap(struct ath11k *ar,
+				    struct ath11k_pdev_cap *cap)
+{
+	struct ieee80211_supported_band *band = NULL;
+	int count = 0;
+
+	if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) {
+		count = ath11k_mac_copy_he_cap(cap,
+				ar->mac.iftype[NL80211_BAND_2GHZ],
+				NL80211_BAND_2GHZ);
+		band = &ar->mac.sbands[NL80211_BAND_2GHZ];
+		band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ];
+	}
+
+	if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
+		count = ath11k_mac_copy_he_cap(cap,
+				ar->mac.iftype[NL80211_BAND_5GHZ],
+				NL80211_BAND_5GHZ);
+		band = &ar->mac.sbands[NL80211_BAND_5GHZ];
+		band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
+	}
+
+	band->n_iftype_data = count;
+}
+
 static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
 {
 	int ret;
@@ -3112,8 +3334,9 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
 		return ret;
 	}
 
-	/* Reload HT/VHT capability */
+	/* Reload HT/VHT/HE capability */
 	ath11k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL);
+	ath11k_mac_setup_he_cap(ar, &ar->pdev->cap);
 
 	return 0;
 }
@@ -4976,6 +5199,7 @@ static int ath11k_mac_register(struct ath11k *ar)
 		goto err_free;
 
 	ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
+	ath11k_mac_setup_he_cap(ar, cap);
 
 	ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask;
 	ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask;
diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c
index 1fef6886088f..d9ff9d631eea 100644
--- a/drivers/net/wireless/ath/ath11k/reg.c
+++ b/drivers/net/wireless/ath/ath11k/reg.c
@@ -138,6 +138,7 @@ int ath11k_reg_update_chan_list(struct ath11k *ar)
 			/* TODO: Set to true/false based on some condition? */
 			ch->allow_ht = true;
 			ch->allow_vht = true;
+			ch->allow_he = true;
 
 			ch->dfs_set =
 				!!(channel->flags & IEEE80211_CHAN_RADAR);
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 807c42d5bb22..05b955a9749f 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -741,6 +741,8 @@ static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan,
 		chan->info |= WMI_CHAN_INFO_ALLOW_HT;
 	if (arg->channel.allow_vht)
 		chan->info |= WMI_CHAN_INFO_ALLOW_VHT;
+	if (arg->channel.allow_he)
+		chan->info |= WMI_CHAN_INFO_ALLOW_HE;
 	if (arg->channel.ht40plus)
 		chan->info |= WMI_CHAN_INFO_HT40_PLUS;
 	if (arg->channel.chan_radar)
@@ -2193,7 +2195,9 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
 
 		if (tchan_info->is_chan_passive)
 			chan_info->info |= WMI_CHAN_INFO_PASSIVE;
-		if (tchan_info->allow_vht)
+		if (tchan_info->allow_he)
+			chan_info->info |= WMI_CHAN_INFO_ALLOW_HE;
+		else if (tchan_info->allow_vht)
 			chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT;
 		else if (tchan_info->allow_ht)
 			chan_info->info |= WMI_CHAN_INFO_ALLOW_HT;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 0fa33f38abdf..2e3e0cf866e9 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -2996,6 +2996,7 @@ struct channel_param {
 	    is_chan_passive:1,
 	    allow_ht:1,
 	    allow_vht:1,
+	    allow_he:1,
 	    set_agile:1;
 	u32 phy_mode;
 	u32 cfreq1;
@@ -3841,7 +3842,10 @@ struct wmi_vdev_install_key_arg {
 
 #define WMI_MAX_SUPPORTED_RATES			128
 #define WMI_HOST_MAX_HECAP_PHY_SIZE		3
-#define WMI_HOST_MAX_HE_RATE_SET		1
+#define WMI_HOST_MAX_HE_RATE_SET		3
+#define WMI_HECAP_TXRX_MCS_NSS_IDX_80		0
+#define WMI_HECAP_TXRX_MCS_NSS_IDX_160		1
+#define WMI_HECAP_TXRX_MCS_NSS_IDX_80_80	2
 
 struct wmi_rate_set_arg {
 	u32 num_rates;
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 5/8] ath11k: extend reading of FW capabilities
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

Read the additional mcs and extended mac capabilities field from the
service ready callback and store them inside the ath11k_pdev_cap
structure. This allows us to generate the sband_iftype_data dynamically.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/core.h | 3 ++-
 drivers/net/wireless/ath/ath11k/wmi.c  | 7 +++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 994170e08cc5..a7c59ea0c228 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -523,7 +523,7 @@ struct ath11k {
 struct ath11k_band_cap {
 	u32 max_bw_supported;
 	u32 ht_cap_info;
-	u32 he_cap_info;
+	u32 he_cap_info[2];
 	u32 he_mcs;
 	u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE];
 	struct ath11k_ppe_threshold he_ppet;
@@ -534,6 +534,7 @@ struct ath11k_pdev_cap {
 	u32 ampdu_density;
 	u32 vht_cap;
 	u32 vht_mcs;
+	u32 he_mcs;
 	u32 tx_chain_mask;
 	u32 rx_chain_mask;
 	u32 tx_chain_mask_shift;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 9ca44c4b24f8..807c42d5bb22 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -325,6 +325,7 @@ static int ath11k_pull_mac_phy_cap_service_ready_ext(
 	} else if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) {
 		pdev_cap->vht_cap = mac_phy_caps->vht_cap_info_5g;
 		pdev_cap->vht_mcs = mac_phy_caps->vht_supp_mcs_5g;
+		pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g;
 		pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g;
 		pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g;
 	} else {
@@ -347,7 +348,8 @@ static int ath11k_pull_mac_phy_cap_service_ready_ext(
 	cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
 	cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g;
 	cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g;
-	cap_band->he_cap_info = mac_phy_caps->he_cap_info_2g;
+	cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g;
+	cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext;
 	cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g;
 	memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g,
 	       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
@@ -357,7 +359,8 @@ static int ath11k_pull_mac_phy_cap_service_ready_ext(
 	cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
 	cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g;
 	cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g;
-	cap_band->he_cap_info = mac_phy_caps->he_cap_info_5g;
+	cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g;
+	cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext;
 	cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g;
 	memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g,
 	       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 7/8] ath11k: handle rx status for HE frames
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

The case clause handling HE frames was not handled yet in the code reading
the RX status. The new case is identical to VHT with the difference of the
higher maximum MCS rate.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/dp_rx.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index e52a54cd2b79..71d385cf55d7 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1727,7 +1727,16 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, void *rx_desc,
 		rx_status->bw = ath11k_bw_to_mac80211_bw(bw);
 		break;
 	case RX_MSDU_START_PKT_TYPE_11AX:
-		ath11k_warn(ar->ab, "pkt_type %d not yet supported\n", pkt_type);
+		rx_status->rate_idx = rate_mcs;
+		if (rate_mcs > ATH11K_HE_MCS_MAX) {
+			ath11k_warn(ar->ab,
+				    "Received with invalid mcs in HE mode %d\n",
+				    rate_mcs);
+			break;
+		}
+		rx_status->encoding = RX_ENC_HE;
+		rx_status->nss = nss;
+		rx_status->bw = ath11k_bw_to_mac80211_bw(bw);
 		break;
 	}
 }
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 4/8] ath11k: add HE handling to the debug code
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

This patch allows the driver to also show the HE counters and stats.
Also extend the appropriate debug prints with HE info.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/core.h        |  2 ++
 drivers/net/wireless/ath/ath11k/debugfs_sta.c | 24 +++++++++++++++++--
 drivers/net/wireless/ath/ath11k/dp_rx.c       |  3 ++-
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 148c9a4c0978..994170e08cc5 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -253,6 +253,7 @@ struct ath11k_peer {
 	struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
 };
 
+#define ATH11K_HE_MCS_NUM       12
 #define ATH11K_VHT_MCS_NUM      10
 #define ATH11K_BW_NUM           4
 #define ATH11K_NSS_NUM          4
@@ -306,6 +307,7 @@ struct ath11k_htt_data_stats {
 	u64 legacy[ATH11K_COUNTER_TYPE_MAX][ATH11K_LEGACY_NUM];
 	u64 ht[ATH11K_COUNTER_TYPE_MAX][ATH11K_HT_MCS_NUM];
 	u64 vht[ATH11K_COUNTER_TYPE_MAX][ATH11K_VHT_MCS_NUM];
+	u64 he[ATH11K_COUNTER_TYPE_MAX][ATH11K_HE_MCS_NUM];
 	u64 bw[ATH11K_COUNTER_TYPE_MAX][ATH11K_BW_NUM];
 	u64 nss[ATH11K_COUNTER_TYPE_MAX][ATH11K_NSS_NUM];
 	u64 gi[ATH11K_COUNTER_TYPE_MAX][ATH11K_GI_NUM];
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
index c39b6e1d22c3..cff6a3f048ea 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -45,7 +45,14 @@ ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
 
 #define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
 
-	if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
+	if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
+		STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
+		STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
+		STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
+		STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
+		STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
+		STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
+	} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
 		STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
 		STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
 		STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
@@ -73,7 +80,12 @@ ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
 	if (peer_stats->is_ampdu) {
 		tx_stats->ba_fails += peer_stats->ba_fails;
 
-		if (txrate->flags & RATE_INFO_FLAGS_MCS) {
+		if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
+			STATS_OP_FMT(AMPDU).he[0][mcs] +=
+			peer_stats->succ_bytes + peer_stats->retry_bytes;
+			STATS_OP_FMT(AMPDU).he[1][mcs] +=
+			peer_stats->succ_pkts + peer_stats->retry_pkts;
+		} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
 			STATS_OP_FMT(AMPDU).ht[0][mcs] +=
 			peer_stats->succ_bytes + peer_stats->retry_bytes;
 			STATS_OP_FMT(AMPDU).ht[1][mcs] +=
@@ -229,6 +241,14 @@ static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
 			len += scnprintf(buf + len, size - len, "%s_%s\n",
 					 str_name[k],
 					 str[j]);
+			len += scnprintf(buf + len, size - len,
+					 " HE MCS %s\n",
+					 str[j]);
+			for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
+				len += scnprintf(buf + len, size - len,
+						 "  %llu ",
+						 stats->he[j][i]);
+			len += scnprintf(buf + len, size - len, "\n");
 			len += scnprintf(buf + len, size - len,
 					 " VHT MCS %s\n",
 					 str[j]);
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 73865ce2b3ab..62820c20f7c1 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1817,7 +1817,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
 	status = IEEE80211_SKB_RXCB(msdu);
 
 	ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
-		   "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+		   "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
 		   msdu,
 		   msdu->len,
 		   ieee80211_get_SA(hdr),
@@ -1828,6 +1828,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
 		   (status->encoding == RX_ENC_LEGACY) ? "legacy" : "",
 		   (status->encoding == RX_ENC_HT) ? "ht" : "",
 		   (status->encoding == RX_ENC_VHT) ? "vht" : "",
+		   (status->encoding == RX_ENC_HE) ? "he" : "",
 		   (status->bw == RATE_INFO_BW_40) ? "40" : "",
 		   (status->bw == RATE_INFO_BW_80) ? "80" : "",
 		   (status->bw == RATE_INFO_BW_160) ? "160" : "",
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 3/8] ath11k: move phymode selection from function to array lookup
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

With HE support getting added, the approach of using functions will quickly
get convoluted. Change the code to use an array lookup function instead.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/mac.c | 117 ++++++++++++--------------
 include/uapi/linux/nl80211.h          |   4 +
 2 files changed, 57 insertions(+), 64 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index cb0de8e2aa60..c5a55fb893ae 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -105,6 +105,52 @@ static struct ieee80211_rate ath11k_legacy_rates[] = {
 	{ .bitrate = 540, .hw_value = ATH11K_HW_RATE_OFDM_54M },
 };
 
+static const int
+ath11k_phymodes[NUM_NL80211_BANDS][2][__NL80211_CHAN_WIDTH_NUM] = {
+	[NL80211_BAND_2GHZ] = {
+		{
+			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11G,
+			[NL80211_CHAN_WIDTH_20] = MODE_11NG_HT20,
+			[NL80211_CHAN_WIDTH_40] = MODE_11NG_HT40,
+			[NL80211_CHAN_WIDTH_80] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN,
+		}, {
+			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11G,
+			[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20_2G,
+			[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40_2G,
+			[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80_2G,
+			[NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN,
+		},
+	},
+	[NL80211_BAND_5GHZ] = {
+		{
+			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11A,
+			[NL80211_CHAN_WIDTH_20] = MODE_11AC_VHT20,
+			[NL80211_CHAN_WIDTH_40] = MODE_11AC_VHT40,
+			[NL80211_CHAN_WIDTH_80] = MODE_11AC_VHT80,
+			[NL80211_CHAN_WIDTH_160] = MODE_11AC_VHT160,
+			[NL80211_CHAN_WIDTH_80P80] = MODE_11AC_VHT80_80,
+		}, {
+			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11A,
+			[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
+			[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
+			[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
+			[NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
+			[NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
+		},
+	},
+};
+
 #define ATH11K_MAC_FIRST_OFDM_RATE_IDX 4
 #define ath11k_g_rates ath11k_legacy_rates
 #define ath11k_g_rates_size (ARRAY_SIZE(ath11k_legacy_rates))
@@ -151,69 +197,6 @@ static int get_num_chains(u32 mask)
 	return num_chains;
 }
 
-static inline enum wmi_phy_mode
-chan_to_phymode(const struct cfg80211_chan_def *chandef)
-{
-	enum wmi_phy_mode phymode = MODE_UNKNOWN;
-
-	switch (chandef->chan->band) {
-	case NL80211_BAND_2GHZ:
-		switch (chandef->width) {
-		case NL80211_CHAN_WIDTH_20_NOHT:
-			if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM)
-				phymode = MODE_11B;
-			else
-				phymode = MODE_11G;
-			break;
-		case NL80211_CHAN_WIDTH_20:
-			phymode = MODE_11NG_HT20;
-			break;
-		case NL80211_CHAN_WIDTH_40:
-			phymode = MODE_11NG_HT40;
-			break;
-		case NL80211_CHAN_WIDTH_5:
-		case NL80211_CHAN_WIDTH_10:
-		case NL80211_CHAN_WIDTH_80:
-		case NL80211_CHAN_WIDTH_80P80:
-		case NL80211_CHAN_WIDTH_160:
-			phymode = MODE_UNKNOWN;
-			break;
-		}
-		break;
-	case NL80211_BAND_5GHZ:
-		switch (chandef->width) {
-		case NL80211_CHAN_WIDTH_20_NOHT:
-			phymode = MODE_11A;
-			break;
-		case NL80211_CHAN_WIDTH_20:
-			phymode = MODE_11AC_VHT20;
-			break;
-		case NL80211_CHAN_WIDTH_40:
-			phymode = MODE_11AC_VHT40;
-			break;
-		case NL80211_CHAN_WIDTH_80:
-			phymode = MODE_11AC_VHT80;
-			break;
-		case NL80211_CHAN_WIDTH_160:
-			phymode = MODE_11AC_VHT160;
-			break;
-		case NL80211_CHAN_WIDTH_80P80:
-			phymode = MODE_11AC_VHT80_80;
-			break;
-		case NL80211_CHAN_WIDTH_5:
-		case NL80211_CHAN_WIDTH_10:
-			phymode = MODE_UNKNOWN;
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-	WARN_ON(phymode == MODE_UNKNOWN);
-	return phymode;
-}
-
 u8 ath11k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
 			     u32 bitrate)
 {
@@ -3881,6 +3864,7 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
 	struct ath11k_base *ab = ar->ab;
 	struct wmi_vdev_start_req_arg arg = {};
 	int ret = 0;
+	int he_support = arvif->vif->bss_conf.he_support;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -3893,7 +3877,12 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
 	arg.channel.freq = chandef->chan->center_freq;
 	arg.channel.band_center_freq1 = chandef->center_freq1;
 	arg.channel.band_center_freq2 = chandef->center_freq2;
-	arg.channel.mode = chan_to_phymode(chandef);
+	arg.channel.mode =
+		ath11k_phymodes[chandef->chan->band][he_support][chandef->width];
+	if (arg.channel.mode == MODE_11G &&
+	    chandef->chan->flags & IEEE80211_CHAN_NO_OFDM)
+		arg.channel.mode = MODE_11B;
+	WARN_ON(arg.channel.mode == MODE_UNKNOWN);
 
 	arg.channel.min_power = 0;
 	arg.channel.max_power = chandef->chan->max_power * 2;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index dd4f86ee286e..b6e29161ec8b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4162,6 +4162,10 @@ enum nl80211_chan_width {
 	NL80211_CHAN_WIDTH_160,
 	NL80211_CHAN_WIDTH_5,
 	NL80211_CHAN_WIDTH_10,
+
+	/* keep last */
+	__NL80211_CHAN_WIDTH_NUM,
+	NL80211_CHAN_WIDTH_MAX = __NL80211_CHAN_WIDTH_NUM - 1,
 };
 
 /**
-- 
2.20.1


^ permalink raw reply related

* [PATCH V5 1/8] mac80211: propagate HE operation info into ieee80211_sta
From: John Crispin @ 2019-05-20  8:55 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath11k, linux-wireless, John Crispin, Shashidhar Lakkavalli
In-Reply-To: <20190520085508.5888-1-john@phrozen.org>

Upon a successful assoc a station shall store the content of the HE
operation element inside ieee80211_sta so that the driver can setup the
hardware accordingly.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
---
 include/net/mac80211.h     |  2 ++
 net/mac80211/he.c          | 14 ++++++++++++++
 net/mac80211/ieee80211_i.h |  5 +++++
 net/mac80211/mlme.c        |  1 +
 4 files changed, 22 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 112dc18c658f..ba4a16f87364 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1903,6 +1903,7 @@ struct ieee80211_sta_rates {
  * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
  * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
  * @he_cap: HE capabilities of this STA
+ * @he_operation: HE operation information of the AP we are connected to
  * @max_rx_aggregation_subframes: maximal amount of frames in a single AMPDU
  *	that this station is allowed to transmit to us.
  *	Can be modified by driver.
@@ -1941,6 +1942,7 @@ struct ieee80211_sta {
 	struct ieee80211_sta_ht_cap ht_cap;
 	struct ieee80211_sta_vht_cap vht_cap;
 	struct ieee80211_sta_he_cap he_cap;
+	struct ieee80211_he_operation he_operation;
 	u16 max_rx_aggregation_subframes;
 	bool wme;
 	u8 uapsd_queues;
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index 769078ed5a12..62ef029e5c48 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -53,3 +53,17 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 
 	he_cap->has_he = true;
 }
+
+void
+ieee80211_he_op_ie_to_sta_he_op(struct ieee80211_sub_if_data *sdata,
+			const struct ieee80211_he_operation *he_op_ie_elem,
+			struct sta_info *sta)
+{
+	struct ieee80211_he_operation *he_operation = &sta->sta.he_operation;
+
+	if (!he_op_ie_elem) {
+		memset(he_operation, 0, sizeof(*he_operation));
+		return;
+	}
+	memcpy(he_operation, he_op_ie_elem, sizeof(*he_operation));
+}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e170f986d226..11bc1778bfd5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1870,6 +1870,11 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 				  const u8 *he_cap_ie, u8 he_cap_len,
 				  struct sta_info *sta);
 
+void
+ieee80211_he_op_ie_to_sta_he_op(struct ieee80211_sub_if_data *sdata,
+			const struct ieee80211_he_operation *he_op_ie_elem,
+			struct sta_info *sta);
+
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 				       struct ieee80211_mgmt *mgmt,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2dbcf5d5512e..5d8a8a0feaf9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3364,6 +3364,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 		if (elems.uora_element)
 			bss_conf->uora_ocw_range = elems.uora_element[0];
 
+		ieee80211_he_op_ie_to_sta_he_op(sdata, elems.he_operation, sta);
 		/* TODO: OPEN: what happens if BSS color disable is set? */
 	}
 
-- 
2.20.1


^ permalink raw reply related

* Re: [PATCH 3/3] iwlwifi: add support for quz firmwares
From: Bjørn Mork @ 2019-05-20  8:42 UTC (permalink / raw)
  To: Luca Coelho; +Cc: kvalo, linux-wireless, Luca Coelho
In-Reply-To: <20190322124744.17924-4-luca@coelho.fi>

Luca Coelho <luca@coelho.fi> writes:

> --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
> +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
> @@ -549,6 +549,7 @@ extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
>  extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
>  extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
>  extern const struct iwl_cfg iwl_ax101_cfg_qu_hr;
> +extern const struct iwl_cfg iwl_ax101_cfg_quz_hr;
>  extern const struct iwl_cfg iwl22000_2ax_cfg_hr;
>  extern const struct iwl_cfg iwl_ax200_cfg_cc;
>  extern const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0;
> diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
> index aea6d03e545a..e539bc94eff7 100644
> --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
> +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
> @@ -327,6 +327,7 @@ enum {
>  #define CSR_HW_REV_TYPE_NONE		(0x00001F0)
>  #define CSR_HW_REV_TYPE_QNJ		(0x0000360)
>  #define CSR_HW_REV_TYPE_QNJ_B0		(0x0000364)
> +#define CSR_HW_REV_TYPE_QUZ		(0x0000354)
>  #define CSR_HW_REV_TYPE_HR_CDB		(0x0000340)
>  #define CSR_HW_REV_TYPE_SO		(0x0000370)
>  #define CSR_HW_REV_TYPE_TY		(0x0000420)
> diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> index 1d6f3053f233..79c1dc05f948 100644
> --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> @@ -3543,6 +3543,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
>  		}
>  	} else if (cfg == &iwl_ax101_cfg_qu_hr) {
>  		if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
> +		    CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) &&
> +		    trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) {
> +			trans->cfg = &iwl22000_2ax_cfg_qnj_hr_b0;
> +		} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
>  		    CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR)) {
>  			trans->cfg = &iwl_ax101_cfg_qu_hr;
>  		} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==

Did you intend to use CSR_HW_REV_TYPE_QUZ and iwl_cfg
iwl_ax101_cfg_quz_hr here, or am I misunderstanding something?

Must admit that I didn't actually read the code.  Just happend to look
at this patch briefly while glancing through linux-wireless...  Sorry if
I'just adding noise.


Bjørn

^ permalink raw reply

* Re: [PATCH 1/3] brcmfmac: re-enable command decode in sdio_aos for BRCM 4354
From: Arend Van Spriel @ 2019-05-20  8:09 UTC (permalink / raw)
  To: Douglas Anderson, Ulf Hansson, Kalle Valo, Adrian Hunter
  Cc: linux-rockchip, Double Lo, briannorris, Madhan Mohan R, mka,
	Wright Feng, Chi-Hsien Lin, brcm80211-dev-list.pdl, Franky Lin,
	netdev, linux-wireless, linux-kernel, Hante Meuleman,
	Naveen Gupta, brcm80211-dev-list, YueHaibing, David S. Miller
In-Reply-To: <20190517225420.176893-2-dianders@chromium.org>



On 5/18/2019 12:54 AM, Douglas Anderson wrote:
> In commit 29f6589140a1 ("brcmfmac: disable command decode in
> sdio_aos") we disabled something called "command decode in sdio_aos"
> for a whole bunch of Broadcom SDIO WiFi parts.
> 
> After that patch landed I find that my kernel log on
> rk3288-veyron-minnie and rk3288-veyron-speedy is filled with:
>    brcmfmac: brcmf_sdio_bus_sleep: error while changing bus sleep state -110
> 
> This seems to happen every time the Broadcom WiFi transitions out of
> sleep mode.  Reverting the part of the commit that affects the WiFi on
> my boards fixes the problem for me, so that's what this patch does.

This sounds very similar to the issue we had during integration of wifi 
on rk3288 chromebooks years ago.

> Note that, in general, the justification in the original commit seemed
> a little weak.  It looked like someone was testing on a SD card
> controller that would sometimes die if there were CRC errors on the
> bus.  This used to happen back in early days of dw_mmc (the controller
> on my boards), but we fixed it.  Disabling a feature on all boards
> just because one SD card controller is broken seems bad.  ...so
> instead of just this patch possibly the right thing to do is to fully
> revert the original commit.

I am leaning towards a full revert, but let's wait for more background info.

Regards,
Arend

^ permalink raw reply

* [PATCH] net: fix typos in code comments
From: Weitao Hou @ 2019-05-19  3:09 UTC (permalink / raw)
  To: nbd, lorenzo.bianconi83, ryder.lee, royluo, kvalo, davem,
	matthias.bgg
  Cc: linux-wireless, netdev, linux-arm-kernel, linux-mediatek,
	linux-kernel, Weitao Hou

fix lenght to length

Signed-off-by: Weitao Hou <houweitaoo@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 6b89f7eab26c..e0f5e6202a27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -53,7 +53,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
 	pad = round_up(skb->len, 4) + 4 - skb->len;
 
 	/* First packet of a A-MSDU burst keeps track of the whole burst
-	 * length, need to update lenght of it and the last packet.
+	 * length, need to update length of it and the last packet.
 	 */
 	skb_walk_frags(skb, iter) {
 		last = iter;
-- 
2.18.0


^ permalink raw reply related

* [PATCH] wireless: fix intel typos in code comments
From: Weitao Hou @ 2019-05-19  3:31 UTC (permalink / raw)
  To: stas.yakovlev, kvalo, davem
  Cc: linux-wireless, netdev, linux-kernel, Weitao Hou

fix lengh to length

Signed-off-by: Weitao Hou <houweitaoo@gmail.com>
---
 drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index fa400f92d7e2..807b2c11215a 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -774,7 +774,7 @@ static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
 		 *
 		 * This table consist of six values, each containing
 		 *     - dword containing the starting offset of the data
-		 *     - dword containing the lengh in the first 16bits
+		 *     - dword containing the length in the first 16bits
 		 *       and the count in the second 16bits
 		 */
 
-- 
2.18.0


^ permalink raw reply related

* [PATCH] wireless: fix typos in code comments
From: Weitao Hou @ 2019-05-19  3:22 UTC (permalink / raw)
  To: arend.vanspriel, franky.lin, hante.meuleman, chi-hsien.lin,
	wright.feng, kvalo, davem, houweitaoo, rafal
  Cc: linux-wireless, brcm80211-dev-list.pdl, brcm80211-dev-list,
	netdev, linux-kernel

fix lengh to length

Signed-off-by: Weitao Hou <houweitaoo@gmail.com>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
index 8ea27489734e..edd2f09613d8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
@@ -314,7 +314,7 @@ brcmf_create_bsscfg(s32 bsscfgidx, char *name, char *data, u32 datalen,
 		return brcmf_create_iovar(name, data, datalen, buf, buflen);
 
 	prefixlen = strlen(prefix);
-	namelen = strlen(name) + 1; /* lengh of iovar  name + null */
+	namelen = strlen(name) + 1; /* length of iovar  name + null */
 	iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen;
 
 	if (buflen < iolen) {
-- 
2.18.0


^ permalink raw reply related

* Re: NXP NFC version and ACPI
From: Daniel Lezcano @ 2019-05-19 16:46 UTC (permalink / raw)
  To: sedat.dilek
  Cc: Samuel Ortiz, linux-wireless, linux-nfc, oleg.zhurakivskyy,
	clement.perrochaud, charles.gorand, Andy Shevchenko
In-Reply-To: <CA+icZUVaBdswfmRfbRtdVJY8ymeDOwDSFEf7G6jneqEmpW84bg@mail.gmail.com>


FYI, when I tried to make the NFC work on my x280, I tried the module at:

https://github.com/jr64/nxp-pn5xx

AFAIR, it finally worked somehow.

May be you can cross check with your series and the change in this
module to find out what could be missing? (I can do that but it will be
certainly easier for you spot something in the code you wrote).

I can experiment your changes in my laptop if needed.


On 14/05/2019 16:59, Sedat Dilek wrote:
> On Tue, May 14, 2019 at 10:17 AM Daniel Lezcano
> <daniel.lezcano@linaro.org> wrote:
> [...]
> 
> Just for the records:
> 
> root@iniza:~# rfkill --output ID,TYPE
> ID TYPE
>  0 bluetooth
>  1 nfc
>  2 wlan
>  3 bluetooth
> 
> root@iniza:~# rfkill list nfc
> 1: nfc0: NFC
>         Soft blocked: no
>         Hard blocked: no
> 
> - Sedat -
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: Christian Lamparter @ 2019-05-18 20:11 UTC (permalink / raw)
  To: Alan Stern
  Cc: syzbot, andreyknvl, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, syzkaller-bugs
In-Reply-To: <Pine.LNX.4.44L0.1905181346380.10594-100000@netrider.rowland.org>

Hello,

On Saturday, May 18, 2019 7:49:49 PM CEST you wrote:
> On Sat, 18 May 2019, syzbot wrote:
> > 
> > syzbot has tested the proposed patch but the reproducer still triggered  
> > crash:
> > KASAN: use-after-free Read in usb_driver_release_interface
> > 
> > usb 1-1: Loading firmware file isl3887usb
> > usb 1-1: Direct firmware load for isl3887usb failed with error -2
> > usb 1-1: Firmware not found.
> > p54usb 1-1:0.143: failed to initialize device (-2)
> > ==================================================================
> > BUG: KASAN: use-after-free in usb_driver_release_interface+0x16b/0x190  
> > drivers/usb/core/driver.c:584
> > Read of size 8 at addr ffff88808fc31218 by task kworker/0:1/12
> 
> Now the bad access is in a different place.  That's a good sign.
> In this case it indicates that although udev is still hanging around, 
> intf has already been freed.  We really should acquire a reference to 
> it instead.
> 
> Alan Stern

Thanks. I can confirm that it works with the real ISL3887 
hardware as well. Can you please spin up a patch or how
should this be continued?

Cheers,
Christian 

>  drivers/net/wireless/intersil/p54/p54usb.c |   43 ++++++++++++-----------------
>  1 file changed, 18 insertions(+), 25 deletions(-)
> 
> Index: usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
> ===================================================================
> --- usb-devel.orig/drivers/net/wireless/intersil/p54/p54usb.c
> +++ usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
> @@ -33,6 +33,8 @@ MODULE_ALIAS("prism54usb");
>  MODULE_FIRMWARE("isl3886usb");
>  MODULE_FIRMWARE("isl3887usb");
>  
> +static struct usb_driver p54u_driver;
> +
>  /*
>   * Note:
>   *
> @@ -921,9 +923,9 @@ static void p54u_load_firmware_cb(const
>  {
>  	struct p54u_priv *priv = context;
>  	struct usb_device *udev = priv->udev;
> +	struct usb_interface *intf = priv->intf;
>  	int err;
>  
> -	complete(&priv->fw_wait_load);
>  	if (firmware) {
>  		priv->fw = firmware;
>  		err = p54u_start_ops(priv);
> @@ -932,26 +934,22 @@ static void p54u_load_firmware_cb(const
>  		dev_err(&udev->dev, "Firmware not found.\n");
>  	}
>  
> -	if (err) {
> -		struct device *parent = priv->udev->dev.parent;
> -
> -		dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
> -
> -		if (parent)
> -			device_lock(parent);
> +	complete(&priv->fw_wait_load);
> +	/*
> +	 * At this point p54u_disconnect may have already freed
> +	 * the "priv" context. Do not use it anymore!
> +	 */
> +	priv = NULL;
>  
> -		device_release_driver(&udev->dev);
> -		/*
> -		 * At this point p54u_disconnect has already freed
> -		 * the "priv" context. Do not use it anymore!
> -		 */
> -		priv = NULL;
> +	if (err) {
> +		dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
>  
> -		if (parent)
> -			device_unlock(parent);
> +		usb_lock_device(udev);
> +		usb_driver_release_interface(&p54u_driver, intf);
> +		usb_unlock_device(udev);
>  	}
>  
> -	usb_put_dev(udev);
> +	usb_put_intf(intf);
>  }
>  
>  static int p54u_load_firmware(struct ieee80211_hw *dev,
> @@ -972,14 +970,14 @@ static int p54u_load_firmware(struct iee
>  	dev_info(&priv->udev->dev, "Loading firmware file %s\n",
>  	       p54u_fwlist[i].fw);
>  
> -	usb_get_dev(udev);
> +	usb_get_intf(intf);
>  	err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
>  				      device, GFP_KERNEL, priv,
>  				      p54u_load_firmware_cb);
>  	if (err) {
>  		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
>  					  "(%d)!\n", p54u_fwlist[i].fw, err);
> -		usb_put_dev(udev);
> +		usb_put_intf(intf);
>  	}
>  
>  	return err;
> @@ -1011,8 +1009,6 @@ static int p54u_probe(struct usb_interfa
>  	skb_queue_head_init(&priv->rx_queue);
>  	init_usb_anchor(&priv->submitted);
>  
> -	usb_get_dev(udev);
> -
>  	/* really lazy and simple way of figuring out if we're a 3887 */
>  	/* TODO: should just stick the identification in the device table */
>  	i = intf->altsetting->desc.bNumEndpoints;
> @@ -1053,10 +1049,8 @@ static int p54u_probe(struct usb_interfa
>  		priv->upload_fw = p54u_upload_firmware_net2280;
>  	}
>  	err = p54u_load_firmware(dev, intf);
> -	if (err) {
> -		usb_put_dev(udev);
> +	if (err)
>  		p54_free_common(dev);
> -	}
>  	return err;
>  }
>  
> @@ -1072,7 +1066,6 @@ static void p54u_disconnect(struct usb_i
>  	wait_for_completion(&priv->fw_wait_load);
>  	p54_unregister_common(dev);
>  
> -	usb_put_dev(interface_to_usbdev(intf));
>  	release_firmware(priv->fw);
>  	p54_free_common(dev);
>  }
> 
> 





^ permalink raw reply

* [PATCH] net: wireless: p54: fix crash during initialization
From: Christian Lamparter @ 2019-05-18 20:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: David S . Miller, Kalle Valo

This patch fixes a crash that got introduced when the
mentioned patch replaced  the direct list_head access
with skb_peek_tail(). When the device is starting up,
there are  no entries in  the queue, so previously to
"Use skb_peek_tail() instead..." the target_skb would
end up as the  tail and head pointer which then could
be used by __skb_queue_after to fill the empty queue.

With skb_peek_tail() in its place will instead just
return NULL which then causes a crash in the
__skb_queue_after().

| BUG: unable to handle kernel NULL pointer dereference at 000000
| #PF error: [normal kernel read fault]
| PGD 0 P4D 0
| Oops: 0000 [#1] SMP PTI
| CPU: 0 PID: 12 Comm: kworker/0:1 Tainted: GO   5.1.0-rc7-wt+ #218
| Hardware name: MSI MS-7816/Z87-G43 (MS-7816), BIOS V1.11 05/09/2015
| Workqueue: events request_firmware_work_func
| RIP: 0010:p54_tx_pending+0x10f/0x1b0 [p54common]
| Code: 78 06 80 78 28 00 74 6d <48> 8b 07 49 89 7c 24 08 49 89 04 24 4
| RSP: 0018:ffffa81c81927d90 EFLAGS: 00010086
| RAX: ffff9bbaaf131048 RBX: 0000000000020670 RCX: 0000000000020264
| RDX: ffff9bbaa976d660 RSI: 0000000000000202 RDI: 0000000000000000
| RBP: ffff9bbaa976d620 R08: 00000000000006c0 R09: ffff9bbaa976d660
| R10: 0000000000000000 R11: ffffe8480dbc5900 R12: ffff9bbb45e87700
| R13: ffff9bbaa976d648 R14: ffff9bbaa976d674 R15: ffff9bbaaf131048
| FS:  0000000000000000(0000) GS:ffff9bbb5ec00000(0000) knlGS:00000
| CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
| CR2: 0000000000000000 CR3: 00000003695fc003 CR4: 00000000001606f0
| Call Trace:
|  p54_download_eeprom+0xbe/0x120 [p54common]
|  p54_read_eeprom+0x7f/0xc0 [p54common]
|  p54u_load_firmware_cb+0xe0/0x160 [p54usb]
|  request_firmware_work_func+0x42/0x80
|  process_one_work+0x1f5/0x3f0
|  worker_thread+0x28/0x3c0

Cc: stable@vger.kernel.org
Fixes: e3554197fc8f ("p54: Use skb_peek_tail() instead of direct head pointer accesses.")
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
 drivers/net/wireless/intersil/p54/txrx.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
index 790784568ad2..5bf1c19ecced 100644
--- a/drivers/net/wireless/intersil/p54/txrx.c
+++ b/drivers/net/wireless/intersil/p54/txrx.c
@@ -142,7 +142,10 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
 	    unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
 		priv->beacon_req_id = data->req_id;
 
-	__skb_queue_after(&priv->tx_queue, target_skb, skb);
+	if (target_skb)
+		__skb_queue_after(&priv->tx_queue, target_skb, skb);
+	else
+		__skb_queue_head(&priv->tx_queue, skb);
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 	return 0;
 }
-- 
2.20.1


^ permalink raw reply related

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: syzbot @ 2019-05-18 18:31 UTC (permalink / raw)
  To: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, stern, syzkaller-bugs
In-Reply-To: <Pine.LNX.4.44L0.1905181346380.10594-100000@netrider.rowland.org>

Hello,

syzbot has tested the proposed patch and the reproducer did not trigger  
crash:

Reported-and-tested-by:  
syzbot+200d4bb11b23d929335f@syzkaller.appspotmail.com

Tested on:

commit:         43151d6c usb-fuzzer: main usb gadget fuzzer driver
git tree:       https://github.com/google/kasan.git usb-fuzzer
kernel config:  https://syzkaller.appspot.com/x/.config?x=4183eeef650d1234
compiler:       gcc (GCC) 9.0.0 20181231 (experimental)
patch:          https://syzkaller.appspot.com/x/patch.diff?x=17e42018a00000

Note: testing is done by a robot and is best-effort only.

^ permalink raw reply

* Re: [PATCH v2 2/2] qtnfmac: add support for Topaz chipsets
From: Jonas Gorski @ 2019-05-18 17:54 UTC (permalink / raw)
  To: Sergey Matyukevich
  Cc: linux-wireless@vger.kernel.org, Igor Mitsyanko, Andrey Shevchenko
In-Reply-To: <20181016102349.26544-3-sergey.matyukevich.os@quantenna.com>

Hi,

On Tue, 16 Oct 2018 at 12:25, Sergey Matyukevich
<sergey.matyukevich.os@quantenna.com> wrote:
>
> This patch adds support for QSR1000/QSR2000 family of chipsets
> to qtnfmac_pcie platform driver.
>
> QSR1000/QSR2000 (aka Topaz) is a family of 80MHz, 11ac Wave2,
> 4x4/2x4/2x2 chips, including single and dual band devices.
> Depending on specific chip model and firmware in use, either
> STA or both STA and AP modes are supported.
>
> Patch adds Topaz support to qtnfmac_pcie driver. Proper platform
> bus will be selected on probing based on chip ID.
>
> Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>
> Signed-off-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
> Signed-off-by: Andrey Shevchenko <ashevchenko@quantenna.com>
> ---

(snip)

> diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
> index 1fe798a9a667..40295a511224 100644
> --- a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
> +++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
> @@ -23,7 +23,7 @@
>
>  /* PCIE Device IDs */
>
> -#define        PCIE_DEVICE_ID_QTN_PEARL        (0x0008)
> +#define        PCIE_DEVICE_ID_QSR              (0x0008)
>
>  #define QTN_REG_SYS_CTRL_CSR           0x14
>  #define QTN_CHIP_ID_MASK               0xF0
> @@ -35,6 +35,8 @@
>  /* FW names */
>
>  #define QTN_PCI_PEARL_FW_NAME          "qtn/fmac_qsr10g.img"
> +#define QTN_PCI_TOPAZ_FW_NAME          "qtn/fmac_qsr1000.img"
> +#define QTN_PCI_TOPAZ_BOOTLD_NAME      "qtn/uboot_qsr1000.img"

A bit late of a review/question, but how does one obtain one of these
files? There's nothing in linux-firmware, and I see only one aborted
attempt for adding fmac_qsr10g.img from 2016, but none for the others.
Searching for these filenames also didn't reveal any external
locations.


Regards
Jonas

^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: Alan Stern @ 2019-05-18 17:49 UTC (permalink / raw)
  To: syzbot
  Cc: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, syzkaller-bugs
In-Reply-To: <000000000000b8203405892cee43@google.com>

On Sat, 18 May 2019, syzbot wrote:

> Hello,
> 
> syzbot has tested the proposed patch but the reproducer still triggered  
> crash:
> KASAN: use-after-free Read in usb_driver_release_interface
> 
> usb 1-1: Loading firmware file isl3887usb
> usb 1-1: Direct firmware load for isl3887usb failed with error -2
> usb 1-1: Firmware not found.
> p54usb 1-1:0.143: failed to initialize device (-2)
> ==================================================================
> BUG: KASAN: use-after-free in usb_driver_release_interface+0x16b/0x190  
> drivers/usb/core/driver.c:584
> Read of size 8 at addr ffff88808fc31218 by task kworker/0:1/12

Now the bad access is in a different place.  That's a good sign.
In this case it indicates that although udev is still hanging around, 
intf has already been freed.  We really should acquire a reference to 
it instead.

Alan Stern


#syz test: https://github.com/google/kasan.git usb-fuzzer

 drivers/net/wireless/intersil/p54/p54usb.c |   43 ++++++++++++-----------------
 1 file changed, 18 insertions(+), 25 deletions(-)

Index: usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
===================================================================
--- usb-devel.orig/drivers/net/wireless/intersil/p54/p54usb.c
+++ usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
@@ -33,6 +33,8 @@ MODULE_ALIAS("prism54usb");
 MODULE_FIRMWARE("isl3886usb");
 MODULE_FIRMWARE("isl3887usb");
 
+static struct usb_driver p54u_driver;
+
 /*
  * Note:
  *
@@ -921,9 +923,9 @@ static void p54u_load_firmware_cb(const
 {
 	struct p54u_priv *priv = context;
 	struct usb_device *udev = priv->udev;
+	struct usb_interface *intf = priv->intf;
 	int err;
 
-	complete(&priv->fw_wait_load);
 	if (firmware) {
 		priv->fw = firmware;
 		err = p54u_start_ops(priv);
@@ -932,26 +934,22 @@ static void p54u_load_firmware_cb(const
 		dev_err(&udev->dev, "Firmware not found.\n");
 	}
 
-	if (err) {
-		struct device *parent = priv->udev->dev.parent;
-
-		dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
-		if (parent)
-			device_lock(parent);
+	complete(&priv->fw_wait_load);
+	/*
+	 * At this point p54u_disconnect may have already freed
+	 * the "priv" context. Do not use it anymore!
+	 */
+	priv = NULL;
 
-		device_release_driver(&udev->dev);
-		/*
-		 * At this point p54u_disconnect has already freed
-		 * the "priv" context. Do not use it anymore!
-		 */
-		priv = NULL;
+	if (err) {
+		dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
 
-		if (parent)
-			device_unlock(parent);
+		usb_lock_device(udev);
+		usb_driver_release_interface(&p54u_driver, intf);
+		usb_unlock_device(udev);
 	}
 
-	usb_put_dev(udev);
+	usb_put_intf(intf);
 }
 
 static int p54u_load_firmware(struct ieee80211_hw *dev,
@@ -972,14 +970,14 @@ static int p54u_load_firmware(struct iee
 	dev_info(&priv->udev->dev, "Loading firmware file %s\n",
 	       p54u_fwlist[i].fw);
 
-	usb_get_dev(udev);
+	usb_get_intf(intf);
 	err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
 				      device, GFP_KERNEL, priv,
 				      p54u_load_firmware_cb);
 	if (err) {
 		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
 					  "(%d)!\n", p54u_fwlist[i].fw, err);
-		usb_put_dev(udev);
+		usb_put_intf(intf);
 	}
 
 	return err;
@@ -1011,8 +1009,6 @@ static int p54u_probe(struct usb_interfa
 	skb_queue_head_init(&priv->rx_queue);
 	init_usb_anchor(&priv->submitted);
 
-	usb_get_dev(udev);
-
 	/* really lazy and simple way of figuring out if we're a 3887 */
 	/* TODO: should just stick the identification in the device table */
 	i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1049,8 @@ static int p54u_probe(struct usb_interfa
 		priv->upload_fw = p54u_upload_firmware_net2280;
 	}
 	err = p54u_load_firmware(dev, intf);
-	if (err) {
-		usb_put_dev(udev);
+	if (err)
 		p54_free_common(dev);
-	}
 	return err;
 }
 
@@ -1072,7 +1066,6 @@ static void p54u_disconnect(struct usb_i
 	wait_for_completion(&priv->fw_wait_load);
 	p54_unregister_common(dev);
 
-	usb_put_dev(interface_to_usbdev(intf));
 	release_firmware(priv->fw);
 	p54_free_common(dev);
 }


^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: syzbot @ 2019-05-18 17:36 UTC (permalink / raw)
  To: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, stern, syzkaller-bugs
In-Reply-To: <Pine.LNX.4.44L0.1905181300440.10594-100000@netrider.rowland.org>

Hello,

syzbot has tested the proposed patch but the reproducer still triggered  
crash:
KASAN: use-after-free Read in usb_driver_release_interface

usb 1-1: Loading firmware file isl3887usb
usb 1-1: Direct firmware load for isl3887usb failed with error -2
usb 1-1: Firmware not found.
p54usb 1-1:0.143: failed to initialize device (-2)
==================================================================
BUG: KASAN: use-after-free in usb_driver_release_interface+0x16b/0x190  
drivers/usb/core/driver.c:584
Read of size 8 at addr ffff88808fc31218 by task kworker/0:1/12

CPU: 0 PID: 12 Comm: kworker/0:1 Not tainted 5.1.0-rc3-g43151d6-dirty #1
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Workqueue: events request_firmware_work_func
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0xe8/0x16e lib/dump_stack.c:113
  print_address_description+0x6c/0x236 mm/kasan/report.c:187
  kasan_report.cold+0x1a/0x3c mm/kasan/report.c:317
  usb_driver_release_interface+0x16b/0x190 drivers/usb/core/driver.c:584
  p54u_load_firmware_cb+0x390/0x420  
drivers/net/wireless/intersil/p54/p54usb.c:948
  request_firmware_work_func+0x12d/0x249  
drivers/base/firmware_loader/main.c:785
  process_one_work+0x90f/0x1580 kernel/workqueue.c:2269
  worker_thread+0x9b/0xe20 kernel/workqueue.c:2415
  kthread+0x313/0x420 kernel/kthread.c:253
  ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352

Allocated by task 12:
  set_track mm/kasan/common.c:87 [inline]
  __kasan_kmalloc mm/kasan/common.c:497 [inline]
  __kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:470
  kmalloc include/linux/slab.h:547 [inline]
  kzalloc include/linux/slab.h:742 [inline]
  usb_set_configuration+0x2e0/0x1740 drivers/usb/core/message.c:1846
  generic_probe+0xa2/0xda drivers/usb/core/generic.c:210
  usb_probe_device+0xc0/0x150 drivers/usb/core/driver.c:266
  really_probe+0x2da/0xb10 drivers/base/dd.c:509
  driver_probe_device+0x21d/0x350 drivers/base/dd.c:671
  __device_attach_driver+0x1d8/0x290 drivers/base/dd.c:778
  bus_for_each_drv+0x163/0x1e0 drivers/base/bus.c:454
  __device_attach+0x223/0x3a0 drivers/base/dd.c:844
  bus_probe_device+0x1f1/0x2a0 drivers/base/bus.c:514
  device_add+0xad2/0x16e0 drivers/base/core.c:2106
  usb_new_device.cold+0x537/0xccf drivers/usb/core/hub.c:2534
  hub_port_connect drivers/usb/core/hub.c:5089 [inline]
  hub_port_connect_change drivers/usb/core/hub.c:5204 [inline]
  port_event drivers/usb/core/hub.c:5350 [inline]
  hub_event+0x138e/0x3b00 drivers/usb/core/hub.c:5432
  process_one_work+0x90f/0x1580 kernel/workqueue.c:2269
  worker_thread+0x9b/0xe20 kernel/workqueue.c:2415
  kthread+0x313/0x420 kernel/kthread.c:253
  ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352

Freed by task 5394:
  set_track mm/kasan/common.c:87 [inline]
  __kasan_slab_free+0x130/0x180 mm/kasan/common.c:459
  slab_free_hook mm/slub.c:1429 [inline]
  slab_free_freelist_hook+0x5e/0x140 mm/slub.c:1456
  slab_free mm/slub.c:3003 [inline]
  kfree+0xce/0x290 mm/slub.c:3958
  device_release+0x7d/0x210 drivers/base/core.c:1064
  kobject_cleanup lib/kobject.c:662 [inline]
  kobject_release lib/kobject.c:691 [inline]
  kref_put include/linux/kref.h:67 [inline]
  kobject_put+0x1df/0x4f0 lib/kobject.c:708
  put_device+0x21/0x30 drivers/base/core.c:2205
  usb_disable_device+0x309/0x790 drivers/usb/core/message.c:1244
  usb_disconnect+0x298/0x870 drivers/usb/core/hub.c:2197
  hub_port_connect drivers/usb/core/hub.c:4940 [inline]
  hub_port_connect_change drivers/usb/core/hub.c:5204 [inline]
  port_event drivers/usb/core/hub.c:5350 [inline]
  hub_event+0xcd2/0x3b00 drivers/usb/core/hub.c:5432
  process_one_work+0x90f/0x1580 kernel/workqueue.c:2269
  worker_thread+0x9b/0xe20 kernel/workqueue.c:2415
  kthread+0x313/0x420 kernel/kthread.c:253
  ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352

The buggy address belongs to the object at ffff88808fc31100
  which belongs to the cache kmalloc-2k of size 2048
The buggy address is located 280 bytes inside of
  2048-byte region [ffff88808fc31100, ffff88808fc31900)
The buggy address belongs to the page:
page:ffffea00023f0c00 count:1 mapcount:0 mapping:ffff88812c3f4800 index:0x0  
compound_mapcount: 0
flags: 0xfff00000010200(slab|head)
raw: 00fff00000010200 dead000000000100 dead000000000200 ffff88812c3f4800
raw: 0000000000000000 00000000000f000f 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
  ffff88808fc31100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff88808fc31180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff88808fc31200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                             ^
  ffff88808fc31280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff88808fc31300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


Tested on:

commit:         43151d6c usb-fuzzer: main usb gadget fuzzer driver
git tree:       https://github.com/google/kasan.git usb-fuzzer
console output: https://syzkaller.appspot.com/x/log.txt?x=148b9428a00000
kernel config:  https://syzkaller.appspot.com/x/.config?x=4183eeef650d1234
compiler:       gcc (GCC) 9.0.0 20181231 (experimental)
patch:          https://syzkaller.appspot.com/x/patch.diff?x=17642018a00000


^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: Alan Stern @ 2019-05-18 17:01 UTC (permalink / raw)
  To: syzbot
  Cc: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, syzkaller-bugs
In-Reply-To: <00000000000043a1f905892c4a1f@google.com>

On Sat, 18 May 2019, syzbot wrote:

> Hello,
> 
> syzbot tried to test the proposed patch but build/boot failed:

One of these times I'll get it right...

Alan Stern


#syz test: https://github.com/google/kasan.git usb-fuzzer

 drivers/net/wireless/intersil/p54/p54usb.c |   37 +++++++++++------------------
 1 file changed, 15 insertions(+), 22 deletions(-)

Index: usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
===================================================================
--- usb-devel.orig/drivers/net/wireless/intersil/p54/p54usb.c
+++ usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
@@ -33,6 +33,8 @@ MODULE_ALIAS("prism54usb");
 MODULE_FIRMWARE("isl3886usb");
 MODULE_FIRMWARE("isl3887usb");
 
+static struct usb_driver p54u_driver;
+
 /*
  * Note:
  *
@@ -921,9 +923,9 @@ static void p54u_load_firmware_cb(const
 {
 	struct p54u_priv *priv = context;
 	struct usb_device *udev = priv->udev;
+	struct usb_interface *intf = priv->intf;
 	int err;
 
-	complete(&priv->fw_wait_load);
 	if (firmware) {
 		priv->fw = firmware;
 		err = p54u_start_ops(priv);
@@ -932,23 +934,19 @@ static void p54u_load_firmware_cb(const
 		dev_err(&udev->dev, "Firmware not found.\n");
 	}
 
-	if (err) {
-		struct device *parent = priv->udev->dev.parent;
-
-		dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
-		if (parent)
-			device_lock(parent);
+	complete(&priv->fw_wait_load);
+	/*
+	 * At this point p54u_disconnect may have already freed
+	 * the "priv" context. Do not use it anymore!
+	 */
+	priv = NULL;
 
-		device_release_driver(&udev->dev);
-		/*
-		 * At this point p54u_disconnect has already freed
-		 * the "priv" context. Do not use it anymore!
-		 */
-		priv = NULL;
+	if (err) {
+		dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
 
-		if (parent)
-			device_unlock(parent);
+		usb_lock_device(udev);
+		usb_driver_release_interface(&p54u_driver, intf);
+		usb_unlock_device(udev);
 	}
 
 	usb_put_dev(udev);
@@ -1011,8 +1009,6 @@ static int p54u_probe(struct usb_interfa
 	skb_queue_head_init(&priv->rx_queue);
 	init_usb_anchor(&priv->submitted);
 
-	usb_get_dev(udev);
-
 	/* really lazy and simple way of figuring out if we're a 3887 */
 	/* TODO: should just stick the identification in the device table */
 	i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1049,8 @@ static int p54u_probe(struct usb_interfa
 		priv->upload_fw = p54u_upload_firmware_net2280;
 	}
 	err = p54u_load_firmware(dev, intf);
-	if (err) {
-		usb_put_dev(udev);
+	if (err)
 		p54_free_common(dev);
-	}
 	return err;
 }
 
@@ -1072,7 +1066,6 @@ static void p54u_disconnect(struct usb_i
 	wait_for_completion(&priv->fw_wait_load);
 	p54_unregister_common(dev);
 
-	usb_put_dev(interface_to_usbdev(intf));
 	release_firmware(priv->fw);
 	p54_free_common(dev);
 }


^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: syzbot @ 2019-05-18 16:50 UTC (permalink / raw)
  To: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, stern, syzkaller-bugs
In-Reply-To: <Pine.LNX.4.44L0.1905181202500.7855-100000@netrider.rowland.org>

Hello,

syzbot tried to test the proposed patch but build/boot failed:

si/sg.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgv100.o
   CC      drivers/scsi/ch.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu102.o
   CC      drivers/scsi/ses.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.o
   CC      drivers/scsi/scsi_sysfs.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/changv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/basegp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/coregv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/wimmgv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/wndwgv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/gv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/user.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/dma/usergv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.o
   AR      drivers/net/ethernet/sun/built-in.a
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.o
   AR      drivers/net/ethernet/built-in.a
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/usergv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.o
scripts/Makefile.build:486: recipe for target 'drivers/net' failed
make[1]: *** [drivers/net] Error 2
make[1]: *** Waiting for unfinished jobs....
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/base.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.o
   CC      drivers/gpu/drm/nouveau/nouveau_acpi.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.o
   CC      drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.o
   CC      drivers/gpu/drm/nouveau/nouveau_debugfs.o
   CC      drivers/gpu/drm/nouveau/nouveau_drm.o
   CC      drivers/gpu/drm/nouveau/nouveau_hwmon.o
   CC      drivers/gpu/drm/nouveau/nouveau_ioc32.o
   CC      drivers/gpu/drm/nouveau/nouveau_led.o
   CC      drivers/gpu/drm/nouveau/nouveau_nvif.o
   CC      drivers/gpu/drm/nouveau/nouveau_usif.o
   CC      drivers/gpu/drm/nouveau/nouveau_bo.o
   CC      drivers/gpu/drm/nouveau/nouveau_gem.o
   CC      drivers/gpu/drm/nouveau/nouveau_mem.o
   CC      drivers/gpu/drm/nouveau/nouveau_backlight.o
   CC      drivers/gpu/drm/nouveau/nouveau_vga.o
   CC      drivers/gpu/drm/nouveau/nouveau_vmm.o
   CC      drivers/gpu/drm/nouveau/nouveau_ttm.o
   CC      drivers/gpu/drm/nouveau/nouveau_bios.o
   CC      drivers/gpu/drm/nouveau/nouveau_prime.o
   CC      drivers/gpu/drm/nouveau/nouveau_connector.o
   CC      drivers/gpu/drm/nouveau/nouveau_sgdma.o
   CC      drivers/gpu/drm/nouveau/nouveau_dp.o
   CC      drivers/gpu/drm/nouveau/nouveau_display.o
   CC      drivers/gpu/drm/nouveau/nv04_fbcon.o
   CC      drivers/gpu/drm/nouveau/nv50_fbcon.o
   CC      drivers/gpu/drm/nouveau/nouveau_fbcon.o
   CC      drivers/gpu/drm/nouveau/nvc0_fbcon.o
   CC      drivers/gpu/drm/nouveau/dispnv04/arb.o
   CC      drivers/gpu/drm/nouveau/dispnv04/crtc.o
   CC      drivers/gpu/drm/nouveau/dispnv04/cursor.o
   CC      drivers/gpu/drm/nouveau/dispnv04/dac.o
   CC      drivers/gpu/drm/nouveau/dispnv04/dfp.o
   CC      drivers/gpu/drm/nouveau/dispnv04/disp.o
   CC      drivers/gpu/drm/nouveau/dispnv04/hw.o
   CC      drivers/gpu/drm/nouveau/dispnv04/overlay.o
   CC      drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.o
   CC      drivers/gpu/drm/nouveau/dispnv04/tvnv04.o
   AR      drivers/scsi/built-in.a
   CC      drivers/gpu/drm/nouveau/dispnv04/tvnv17.o
   CC      drivers/gpu/drm/nouveau/dispnv50/disp.o
   CC      drivers/gpu/drm/nouveau/dispnv50/lut.o
   CC      drivers/gpu/drm/nouveau/dispnv50/core507d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/core.o
   CC      drivers/gpu/drm/nouveau/dispnv50/core907d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/core827d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/core917d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/corec37d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/corec57d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/dac907d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/dac507d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/pior507d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/sor507d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/sor907d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/sorc37d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/head.o
   CC      drivers/gpu/drm/nouveau/dispnv50/head507d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/head827d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/head907d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/headc37d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/head917d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/headc57d.o
   CC      drivers/gpu/drm/nouveau/dispnv50/wimm.o
   CC      drivers/gpu/drm/nouveau/dispnv50/wimmc37b.o
   CC      drivers/gpu/drm/nouveau/dispnv50/wndwc37e.o
   CC      drivers/gpu/drm/nouveau/dispnv50/base.o
   CC      drivers/gpu/drm/nouveau/dispnv50/wndwc57e.o
   CC      drivers/gpu/drm/nouveau/dispnv50/wndw.o
   CC      drivers/gpu/drm/nouveau/dispnv50/base907c.o
   CC      drivers/gpu/drm/nouveau/dispnv50/base827c.o
   CC      drivers/gpu/drm/nouveau/dispnv50/base507c.o
   CC      drivers/gpu/drm/nouveau/dispnv50/base917c.o
   CC      drivers/gpu/drm/nouveau/dispnv50/curs.o
   CC      drivers/gpu/drm/nouveau/dispnv50/curs507a.o
   CC      drivers/gpu/drm/nouveau/dispnv50/curs907a.o
   CC      drivers/gpu/drm/nouveau/dispnv50/cursc37a.o
   CC      drivers/gpu/drm/nouveau/dispnv50/oimm.o
   CC      drivers/gpu/drm/nouveau/dispnv50/oimm507b.o
   CC      drivers/gpu/drm/nouveau/dispnv50/ovly.o
   CC      drivers/gpu/drm/nouveau/dispnv50/ovly507e.o
   CC      drivers/gpu/drm/nouveau/dispnv50/ovly827e.o
   CC      drivers/gpu/drm/nouveau/dispnv50/ovly907e.o
   CC      drivers/gpu/drm/nouveau/dispnv50/ovly917e.o
   CC      drivers/gpu/drm/nouveau/nouveau_abi16.o
   CC      drivers/gpu/drm/nouveau/nouveau_chan.o
   CC      drivers/gpu/drm/nouveau/nv04_fence.o
   CC      drivers/gpu/drm/nouveau/nouveau_fence.o
   CC      drivers/gpu/drm/nouveau/nouveau_dma.o
   CC      drivers/gpu/drm/nouveau/nv10_fence.o
   CC      drivers/gpu/drm/nouveau/nv50_fence.o
   CC      drivers/gpu/drm/nouveau/nv17_fence.o
   CC      drivers/gpu/drm/nouveau/nv84_fence.o
   CC      drivers/gpu/drm/nouveau/nvc0_fence.o
   AR      drivers/gpu/drm/nouveau/built-in.a
   AR      drivers/gpu/drm/built-in.a
   AR      drivers/gpu/built-in.a
Makefile:1051: recipe for target 'drivers' failed
make: *** [drivers] Error 2


Error text is too large and was truncated, full error text is at:
https://syzkaller.appspot.com/x/error.txt?x=164a0108a00000


Tested on:

commit:         43151d6c usb-fuzzer: main usb gadget fuzzer driver
git tree:       https://github.com/google/kasan.git usb-fuzzer
compiler:       gcc (GCC) 9.0.0 20181231 (experimental)
patch:          https://syzkaller.appspot.com/x/patch.diff?x=15d1ef02a00000


^ permalink raw reply

* Re: KASAN: use-after-free Read in p54u_load_firmware_cb
From: Alan Stern @ 2019-05-18 16:32 UTC (permalink / raw)
  To: syzbot
  Cc: andreyknvl, chunkeey, chunkeey, davem, kvalo, linux-kernel,
	linux-usb, linux-wireless, netdev, oneukum, syzkaller-bugs
In-Reply-To: <000000000000add98105892b73ec@google.com>

On Sat, 18 May 2019, syzbot wrote:

> Hello,
> 
> syzbot has tested the proposed patch but the reproducer still triggered  
> crash:
> KASAN: slab-out-of-bounds Read in p54u_load_firmware_cb
> 
> usb 6-1: Direct firmware load for isl3887usb failed with error -2
> p54u_load_firmware_cb: priv->udev = ffff88809ad5bb80
> usb 6-1: Firmware not found.
> ==================================================================
> BUG: KASAN: slab-out-of-bounds in p54u_load_firmware_cb+0x3c9/0x45f  
> drivers/net/wireless/intersil/p54/p54usb.c:937
> Read of size 8 at addr ffff88809abab588 by task kworker/1:8/5526

If you look at the full console log, you'll see that this address is 
different from all the addresses printed out earlier.  Not what you 
would expect.

Which makes me wonder: Suppose a disconnect occurs before the firmware 
loader callback runs?  p54_disconnect() will get stuck waiting for the 
priv->fw_load_wait completion to fire.  But when the callback runs, the 
first thing it does is activate the completion.

So now p54_disconnect() can finish doing its thing, including 
deallocating all the private data structures.  Then when 
p54u_load_firmware_cb() tries to read the contents of priv, it ends up 
accessing deallocated memory!

The patch below tries to do things the right way.

Alan Stern


#syz test: https://github.com/google/kasan.git usb-fuzzer

 drivers/net/wireless/intersil/p54/p54usb.c |   37 +++++++++++------------------
 1 file changed, 15 insertions(+), 22 deletions(-)

Index: usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
===================================================================
--- usb-devel.orig/drivers/net/wireless/intersil/p54/p54usb.c
+++ usb-devel/drivers/net/wireless/intersil/p54/p54usb.c
@@ -33,6 +33,8 @@ MODULE_ALIAS("prism54usb");
 MODULE_FIRMWARE("isl3886usb");
 MODULE_FIRMWARE("isl3887usb");
 
+static struct usb_driver p54u_driver;
+
 /*
  * Note:
  *
@@ -921,9 +923,9 @@ static void p54u_load_firmware_cb(const
 {
 	struct p54u_priv *priv = context;
 	struct usb_device *udev = priv->udev;
+	struct usb_interface *intf = priv->intf;
 	int err;
 
-	complete(&priv->fw_wait_load);
 	if (firmware) {
 		priv->fw = firmware;
 		err = p54u_start_ops(priv);
@@ -932,23 +934,19 @@ static void p54u_load_firmware_cb(const
 		dev_err(&udev->dev, "Firmware not found.\n");
 	}
 
-	if (err) {
-		struct device *parent = priv->udev->dev.parent;
-
-		dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
-		if (parent)
-			device_lock(parent);
+	complete(&priv->fw_wait_load);
+	/*
+	 * At this point p54u_disconnect may have already freed
+	 * the "priv" context. Do not use it anymore!
+	 */
+	priv = NULL;
 
-		device_release_driver(&udev->dev);
-		/*
-		 * At this point p54u_disconnect has already freed
-		 * the "priv" context. Do not use it anymore!
-		 */
-		priv = NULL;
+	if (err) {
+		dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
 
-		if (parent)
-			device_unlock(parent);
+		usb_lock_device(udev);
+		usb_driver_release_interface(intf, &p54u_driver);
+		usb_unlock_device(udev);
 	}
 
 	usb_put_dev(udev);
@@ -1011,8 +1009,6 @@ static int p54u_probe(struct usb_interfa
 	skb_queue_head_init(&priv->rx_queue);
 	init_usb_anchor(&priv->submitted);
 
-	usb_get_dev(udev);
-
 	/* really lazy and simple way of figuring out if we're a 3887 */
 	/* TODO: should just stick the identification in the device table */
 	i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1049,8 @@ static int p54u_probe(struct usb_interfa
 		priv->upload_fw = p54u_upload_firmware_net2280;
 	}
 	err = p54u_load_firmware(dev, intf);
-	if (err) {
-		usb_put_dev(udev);
+	if (err)
 		p54_free_common(dev);
-	}
 	return err;
 }
 
@@ -1072,7 +1066,6 @@ static void p54u_disconnect(struct usb_i
 	wait_for_completion(&priv->fw_wait_load);
 	p54_unregister_common(dev);
 
-	usb_put_dev(interface_to_usbdev(intf));
 	release_firmware(priv->fw);
 	p54_free_common(dev);
 }


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox