diff options
Diffstat (limited to 'drivers/net/wireless/broadcom')
23 files changed, 750 insertions, 181 deletions
diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index 9fc7c088a539..67b4bac048e5 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -651,7 +651,7 @@ struct b43_iv {  	union {  		__be16 d16;  		__be32 d32; -	} data __packed; +	} __packed data;  } __packed; diff --git a/drivers/net/wireless/broadcom/b43legacy/b43legacy.h b/drivers/net/wireless/broadcom/b43legacy/b43legacy.h index 6b0cec467938..f49365d14619 100644 --- a/drivers/net/wireless/broadcom/b43legacy/b43legacy.h +++ b/drivers/net/wireless/broadcom/b43legacy/b43legacy.h @@ -379,7 +379,7 @@ struct b43legacy_iv {  	union {  		__be16 d16;  		__be32 d32; -	} data __packed; +	} __packed data;  } __packed;  #define B43legacy_PHYMODE(phytype)	(1 << (phytype)) diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index 6869f2bf1bae..60e41de72f29 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -127,14 +127,6 @@ static inline int next_slot(struct b43legacy_dmaring *ring, int slot)  	return slot + 1;  } -static inline int prev_slot(struct b43legacy_dmaring *ring, int slot) -{ -	B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); -	if (slot == 0) -		return ring->nr_slots - 1; -	return slot - 1; -} -  #ifdef CONFIG_B43LEGACY_DEBUG  static void update_max_used_slots(struct b43legacy_dmaring *ring,  				  int current_used_slots) diff --git a/drivers/net/wireless/broadcom/b43legacy/radio.c b/drivers/net/wireless/broadcom/b43legacy/radio.c index fdf78c10a05c..8d7eb89c1628 100644 --- a/drivers/net/wireless/broadcom/b43legacy/radio.c +++ b/drivers/net/wireless/broadcom/b43legacy/radio.c @@ -1709,23 +1709,6 @@ u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)  	return ret;  } -static inline -u16 freq_r3A_value(u16 frequency) -{ -	u16 value; - -	if (frequency < 5091) -		value = 0x0040; -	else if (frequency < 5321) -		value = 0x0000; -	else if (frequency < 5806) -		value = 0x0080; -	else -		value = 0x0040; - -	return value; -} -  int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,  				  u8 channel,  				  int synthetic_pu_workaround) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index 0e996cf24f88..dc6d27a36faa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -48,6 +48,8 @@ brcmfmac-$(CONFIG_OF) += \  		of.o  brcmfmac-$(CONFIG_DMI) += \  		dmi.o +brcmfmac-$(CONFIG_ACPI) += \ +		acpi.o  ifeq ($(CONFIG_BRCMFMAC),m)  obj-m += wcc/ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c new file mode 100644 index 000000000000..c4a54861bfb4 --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright The Asahi Linux Contributors + */ + +#include <linux/acpi.h> +#include "debug.h" +#include "core.h" +#include "common.h" + +void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type, +		      struct brcmf_mp_device *settings) +{ +	acpi_status status; +	const union acpi_object *o; +	struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; +	struct acpi_device *adev = ACPI_COMPANION(dev); + +	if (!adev) +		return; + +	if (!ACPI_FAILURE(acpi_dev_get_property(adev, "module-instance", +						ACPI_TYPE_STRING, &o))) { +		brcmf_dbg(INFO, "ACPI module-instance=%s\n", o->string.pointer); +		settings->board_type = devm_kasprintf(dev, GFP_KERNEL, +						      "apple,%s", +						      o->string.pointer); +	} else { +		brcmf_dbg(INFO, "No ACPI module-instance\n"); +		return; +	} + +	status = acpi_evaluate_object(adev->handle, "RWCV", NULL, &buf); +	o = buf.pointer; +	if (!ACPI_FAILURE(status) && o && o->type == ACPI_TYPE_BUFFER && +	    o->buffer.length >= 2) { +		char *antenna_sku = devm_kzalloc(dev, 3, GFP_KERNEL); + +		if (antenna_sku) { +			memcpy(antenna_sku, o->buffer.pointer, 2); +			brcmf_dbg(INFO, "ACPI RWCV data=%*phN antenna-sku=%s\n", +				  (int)o->buffer.length, o->buffer.pointer, +				  antenna_sku); +			settings->antenna_sku = antenna_sku; +		} + +		kfree(buf.pointer); +	} else { +		brcmf_dbg(INFO, "No ACPI antenna-sku\n"); +	} +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index b7c918f241c9..00679a990e3d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -965,6 +965,12 @@ out:  		.driver_data = BRCMF_FWVENDOR_ ## fw_vend \  	} +#define CYW_SDIO_DEVICE(dev_id, fw_vend) \ +	{ \ +		SDIO_DEVICE(SDIO_VENDOR_ID_CYPRESS, dev_id), \ +		.driver_data = BRCMF_FWVENDOR_ ## fw_vend \ +	} +  /* devices we support, null terminated */  static const struct sdio_device_id brcmf_sdmmc_ids[] = {  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143, WCC), @@ -979,6 +985,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC), +	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43439, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC), @@ -986,23 +993,42 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW), -	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW),  	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW), +	CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),  	{ /* end: all zeroes */ }  };  MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); -static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev, -						  int val) +static void brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev *sdiodev)  {  #if IS_ENABLED(CONFIG_ACPI)  	struct acpi_device *adev; -	adev = ACPI_COMPANION(dev); +	adev = ACPI_COMPANION(&sdiodev->func1->dev); +	if (adev) +		sdiodev->func1_power_manageable = adev->flags.power_manageable; + +	adev = ACPI_COMPANION(&sdiodev->func2->dev);  	if (adev) -		adev->flags.power_manageable = 0; +		sdiodev->func2_power_manageable = adev->flags.power_manageable; +#endif +} + +static void brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev *sdiodev, +						  int enable) +{ +#if IS_ENABLED(CONFIG_ACPI) +	struct acpi_device *adev; + +	adev = ACPI_COMPANION(&sdiodev->func1->dev); +	if (adev) +		adev->flags.power_manageable = enable ? sdiodev->func1_power_manageable : 0; + +	adev = ACPI_COMPANION(&sdiodev->func2->dev); +	if (adev) +		adev->flags.power_manageable = enable ? sdiodev->func2_power_manageable : 0;  #endif  } @@ -1012,7 +1038,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,  	int err;  	struct brcmf_sdio_dev *sdiodev;  	struct brcmf_bus *bus_if; -	struct device *dev; + +	if (!id) { +		dev_err(&func->dev, "Error no sdio_device_id passed for %x:%x\n", func->vendor, func->device); +		return -ENODEV; +	}  	brcmf_dbg(SDIO, "Enter\n");  	brcmf_dbg(SDIO, "Class=%x\n", func->class); @@ -1020,14 +1050,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,  	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);  	brcmf_dbg(SDIO, "Function#: %d\n", func->num); -	dev = &func->dev; -  	/* Set MMC_QUIRK_LENIENT_FN0 for this card */  	func->card->quirks |= MMC_QUIRK_LENIENT_FN0; -	/* prohibit ACPI power management for this device */ -	brcmf_sdiod_acpi_set_power_manageable(dev, 0); -  	/* Consume func num 1 but dont do anything with it. */  	if (func->num == 1)  		return 0; @@ -1059,6 +1084,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,  	dev_set_drvdata(&sdiodev->func1->dev, bus_if);  	sdiodev->dev = &sdiodev->func1->dev; +	brcmf_sdiod_acpi_save_power_manageable(sdiodev);  	brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);  	brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); @@ -1124,6 +1150,8 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)  	if (sdiodev->settings->bus.sdio.oob_irq_supported ||  	    pm_caps & MMC_PM_WAKE_SDIO_IRQ) { +		/* Stop ACPI from turning off the device when wowl is enabled */ +		brcmf_sdiod_acpi_set_power_manageable(sdiodev, !enabled);  		sdiodev->wowl_enabled = enabled;  		brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);  		return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 501136e011b5..fe31051a9e11 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -55,6 +55,7 @@ enum brcmf_bus_protocol_type {  /* Firmware blobs that may be available */  enum brcmf_blob_type {  	BRCMF_BLOB_CLM, +	BRCMF_BLOB_TXCAP,  };  struct brcmf_mp_device; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index a9690ec4c850..de8a2e27f49c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1039,12 +1039,134 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)  	}  } +static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le, +				       struct brcmf_scan_params_le *params_le) +{ +	size_t params_size; +	u32 ch; +	int n_channels, n_ssids; + +	memcpy(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le, +	       sizeof(params_le->ssid_le)); +	memcpy(¶ms_le->bssid, ¶ms_v2_le->bssid, +	       sizeof(params_le->bssid)); + +	params_le->bss_type = params_v2_le->bss_type; +	params_le->scan_type = le32_to_cpu(params_v2_le->scan_type); +	params_le->nprobes = params_v2_le->nprobes; +	params_le->active_time = params_v2_le->active_time; +	params_le->passive_time = params_v2_le->passive_time; +	params_le->home_time = params_v2_le->home_time; +	params_le->channel_num = params_v2_le->channel_num; + +	ch = le32_to_cpu(params_v2_le->channel_num); +	n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK; +	n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT; + +	params_size = sizeof(u16) * n_channels; +	if (n_ssids > 0) { +		params_size = roundup(params_size, sizeof(u32)); +		params_size += sizeof(struct brcmf_ssid_le) * n_ssids; +	} + +	memcpy(¶ms_le->channel_list[0], +	       ¶ms_v2_le->channel_list[0], params_size); +} + +static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, +			     struct brcmf_scan_params_v2_le *params_le, +			     struct cfg80211_scan_request *request) +{ +	u32 n_ssids; +	u32 n_channels; +	s32 i; +	s32 offset; +	u16 chanspec; +	char *ptr; +	int length; +	struct brcmf_ssid_le ssid_le; + +	eth_broadcast_addr(params_le->bssid); + +	length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE; + +	params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2); +	params_le->bss_type = DOT11_BSSTYPE_ANY; +	params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE); +	params_le->channel_num = 0; +	params_le->nprobes = cpu_to_le32(-1); +	params_le->active_time = cpu_to_le32(-1); +	params_le->passive_time = cpu_to_le32(-1); +	params_le->home_time = cpu_to_le32(-1); +	memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le)); + +	/* Scan abort */ +	if (!request) { +		length += sizeof(u16); +		params_le->channel_num = cpu_to_le32(1); +		params_le->channel_list[0] = cpu_to_le16(-1); +		params_le->length = cpu_to_le16(length); +		return; +	} + +	n_ssids = request->n_ssids; +	n_channels = request->n_channels; + +	/* Copy channel array if applicable */ +	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n", +		  n_channels); +	if (n_channels > 0) { +		length += roundup(sizeof(u16) * n_channels, sizeof(u32)); +		for (i = 0; i < n_channels; i++) { +			chanspec = channel_to_chanspec(&cfg->d11inf, +						       request->channels[i]); +			brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n", +				  request->channels[i]->hw_value, chanspec); +			params_le->channel_list[i] = cpu_to_le16(chanspec); +		} +	} else { +		brcmf_dbg(SCAN, "Scanning all channels\n"); +	} + +	/* Copy ssid array if applicable */ +	brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids); +	if (n_ssids > 0) { +		offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) + +				n_channels * sizeof(u16); +		offset = roundup(offset, sizeof(u32)); +		length += sizeof(ssid_le) * n_ssids, +		ptr = (char *)params_le + offset; +		for (i = 0; i < n_ssids; i++) { +			memset(&ssid_le, 0, sizeof(ssid_le)); +			ssid_le.SSID_len = +					cpu_to_le32(request->ssids[i].ssid_len); +			memcpy(ssid_le.SSID, request->ssids[i].ssid, +			       request->ssids[i].ssid_len); +			if (!ssid_le.SSID_len) +				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i); +			else +				brcmf_dbg(SCAN, "%d: scan for  %.32s size=%d\n", +					  i, ssid_le.SSID, ssid_le.SSID_len); +			memcpy(ptr, &ssid_le, sizeof(ssid_le)); +			ptr += sizeof(ssid_le); +		} +	} else { +		brcmf_dbg(SCAN, "Performing passive scan\n"); +		params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE); +	} +	params_le->length = cpu_to_le16(length); +	/* Adding mask to channel numbers */ +	params_le->channel_num = +		cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) | +			(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK)); +} +  s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  				struct brcmf_if *ifp, bool aborted,  				bool fw_abort)  {  	struct brcmf_pub *drvr = cfg->pub; -	struct brcmf_scan_params_le params_le; +	struct brcmf_scan_params_v2_le params_v2_le;  	struct cfg80211_scan_request *scan_request;  	u64 reqid;  	u32 bucket; @@ -1063,20 +1185,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  	if (fw_abort) {  		/* Do a scan abort to stop the driver's scan engine */  		brcmf_dbg(SCAN, "ABORT scan in firmware\n"); -		memset(¶ms_le, 0, sizeof(params_le)); -		eth_broadcast_addr(params_le.bssid); -		params_le.bss_type = DOT11_BSSTYPE_ANY; -		params_le.scan_type = 0; -		params_le.channel_num = cpu_to_le32(1); -		params_le.nprobes = cpu_to_le32(1); -		params_le.active_time = cpu_to_le32(-1); -		params_le.passive_time = cpu_to_le32(-1); -		params_le.home_time = cpu_to_le32(-1); -		/* Scan is aborted by setting channel_list[0] to -1 */ -		params_le.channel_list[0] = cpu_to_le16(-1); + +		brcmf_escan_prep(cfg, ¶ms_v2_le, NULL); +  		/* E-Scan (or anyother type) can be aborted by SCAN */ -		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, -					     ¶ms_le, sizeof(params_le)); +		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { +			err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, +						     ¶ms_v2_le, +						     sizeof(params_v2_le)); +		} else { +			struct brcmf_scan_params_le params_le; + +			brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le); +			err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, +						     ¶ms_le, +						     sizeof(params_le)); +		} +  		if (err)  			bphy_err(drvr, "Scan abort failed\n");  	} @@ -1295,83 +1420,13 @@ done:  	return err;  } -static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, -			     struct brcmf_scan_params_le *params_le, -			     struct cfg80211_scan_request *request) -{ -	u32 n_ssids; -	u32 n_channels; -	s32 i; -	s32 offset; -	u16 chanspec; -	char *ptr; -	struct brcmf_ssid_le ssid_le; - -	eth_broadcast_addr(params_le->bssid); -	params_le->bss_type = DOT11_BSSTYPE_ANY; -	params_le->scan_type = BRCMF_SCANTYPE_ACTIVE; -	params_le->channel_num = 0; -	params_le->nprobes = cpu_to_le32(-1); -	params_le->active_time = cpu_to_le32(-1); -	params_le->passive_time = cpu_to_le32(-1); -	params_le->home_time = cpu_to_le32(-1); -	memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le)); - -	n_ssids = request->n_ssids; -	n_channels = request->n_channels; - -	/* Copy channel array if applicable */ -	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n", -		  n_channels); -	if (n_channels > 0) { -		for (i = 0; i < n_channels; i++) { -			chanspec = channel_to_chanspec(&cfg->d11inf, -						       request->channels[i]); -			brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n", -				  request->channels[i]->hw_value, chanspec); -			params_le->channel_list[i] = cpu_to_le16(chanspec); -		} -	} else { -		brcmf_dbg(SCAN, "Scanning all channels\n"); -	} -	/* Copy ssid array if applicable */ -	brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids); -	if (n_ssids > 0) { -		offset = offsetof(struct brcmf_scan_params_le, channel_list) + -				n_channels * sizeof(u16); -		offset = roundup(offset, sizeof(u32)); -		ptr = (char *)params_le + offset; -		for (i = 0; i < n_ssids; i++) { -			memset(&ssid_le, 0, sizeof(ssid_le)); -			ssid_le.SSID_len = -					cpu_to_le32(request->ssids[i].ssid_len); -			memcpy(ssid_le.SSID, request->ssids[i].ssid, -			       request->ssids[i].ssid_len); -			if (!ssid_le.SSID_len) -				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i); -			else -				brcmf_dbg(SCAN, "%d: scan for  %.32s size=%d\n", -					  i, ssid_le.SSID, ssid_le.SSID_len); -			memcpy(ptr, &ssid_le, sizeof(ssid_le)); -			ptr += sizeof(ssid_le); -		} -	} else { -		brcmf_dbg(SCAN, "Performing passive scan\n"); -		params_le->scan_type = BRCMF_SCANTYPE_PASSIVE; -	} -	/* Adding mask to channel numbers */ -	params_le->channel_num = -		cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) | -			(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK)); -} -  static s32  brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,  		struct cfg80211_scan_request *request)  {  	struct brcmf_pub *drvr = cfg->pub; -	s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + -			  offsetof(struct brcmf_escan_params_le, params_le); +	s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE + +			  offsetof(struct brcmf_escan_params_le, params_v2_le);  	struct brcmf_escan_params_le *params;  	s32 err = 0; @@ -1391,8 +1446,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,  		goto exit;  	}  	BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN); -	brcmf_escan_prep(cfg, ¶ms->params_le, request); -	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); +	brcmf_escan_prep(cfg, ¶ms->params_v2_le, request); + +	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2); + +	if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { +		struct brcmf_escan_params_le *params_v1; + +		params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE; +		params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE; +		params_v1 = kzalloc(params_size, GFP_KERNEL); +		params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); +		brcmf_scan_params_v2_to_v1(¶ms->params_v2_le, ¶ms_v1->params_le); +		kfree(params); +		params = params_v1; +	} +  	params->action = cpu_to_le16(WL_ESCAN_ACTION_START);  	params->sync_id = cpu_to_le16(0x1234); @@ -1617,13 +1686,14 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)  {  	struct brcmf_pub *drvr = ifp->drvr;  	struct brcmf_wsec_pmk_le pmk; -	int i, err; +	int err; + +	memset(&pmk, 0, sizeof(pmk)); -	/* convert to firmware key format */ -	pmk.key_len = cpu_to_le16(pmk_len << 1); -	pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE); -	for (i = 0; i < pmk_len; i++) -		snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]); +	/* pass pmk directly */ +	pmk.key_len = cpu_to_le16(pmk_len); +	pmk.flags = cpu_to_le16(0); +	memcpy(pmk.key, pmk_data, pmk_len);  	/* store psk in firmware */  	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, @@ -4237,6 +4307,37 @@ exit:  	return 0;  } +static s32 +brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, +		  bool alive) +{ +	struct brcmf_pmk_op_v3_le *pmk_op; +	int length = offsetof(struct brcmf_pmk_op_v3_le, pmk); +	int ret; + +	pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL); +	pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3); + +	if (!pmksa) { +		/* Flush operation, operate on entire list */ +		pmk_op->count = cpu_to_le16(0); +	} else { +		/* Single PMK operation */ +		pmk_op->count = cpu_to_le16(1); +		length += sizeof(struct brcmf_pmksa_v3); +		memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN); +		memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); +		pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN; +		pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0); +	} + +	pmk_op->length = cpu_to_le16(length); + +	ret = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_op, sizeof(*pmk_op)); +	kfree(pmk_op); +	return ret; +} +  static __used s32  brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)  { @@ -4270,6 +4371,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,  	if (!check_vif_up(ifp->vif))  		return -EIO; +	brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmksa->bssid); +	brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmksa->pmkid); + +	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) +		return brcmf_pmksa_v3_op(ifp, pmksa, true); + +	/* TODO: implement PMKID_V2 */ +  	npmk = le32_to_cpu(cfg->pmk_list.npmk);  	for (i = 0; i < npmk; i++)  		if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) @@ -4286,9 +4395,6 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,  		return -EINVAL;  	} -	brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid); -	brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmk[npmk].pmkid); -  	err = brcmf_update_pmklist(cfg, ifp);  	brcmf_dbg(TRACE, "Exit\n"); @@ -4312,6 +4418,11 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,  	brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid); +	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) +		return brcmf_pmksa_v3_op(ifp, pmksa, false); + +	/* TODO: implement PMKID_V2 */ +  	npmk = le32_to_cpu(cfg->pmk_list.npmk);  	for (i = 0; i < npmk; i++)  		if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) @@ -4348,6 +4459,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)  	if (!check_vif_up(ifp->vif))  		return -EIO; +	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) +		return brcmf_pmksa_v3_op(ifp, NULL, false); + +	/* TODO: implement PMKID_V2 */ +  	memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));  	err = brcmf_update_pmklist(cfg, ifp); @@ -6164,6 +6280,11 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,  		(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;  	req_len = le32_to_cpu(assoc_info->req_len);  	resp_len = le32_to_cpu(assoc_info->resp_len); +	if (req_len > WL_EXTRA_BUF_MAX || resp_len > WL_EXTRA_BUF_MAX) { +		bphy_err(drvr, "invalid lengths in assoc info: req %u resp %u\n", +			 req_len, resp_len); +		return -EINVAL; +	}  	if (req_len) {  		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",  					       cfg->extra_buf, @@ -6489,18 +6610,20 @@ static s32 brcmf_notify_rssi(struct brcmf_if *ifp,  {  	struct brcmf_cfg80211_vif *vif = ifp->vif;  	struct brcmf_rssi_be *info = data; -	s32 rssi, snr, noise; +	s32 rssi, snr = 0, noise = 0;  	s32 low, high, last; -	if (e->datalen < sizeof(*info)) { +	if (e->datalen >= sizeof(*info)) { +		rssi = be32_to_cpu(info->rssi); +		snr = be32_to_cpu(info->snr); +		noise = be32_to_cpu(info->noise); +	} else if (e->datalen >= sizeof(rssi)) { +		rssi = be32_to_cpu(*(__be32 *)data); +	} else {  		brcmf_err("insufficient RSSI event data\n");  		return 0;  	} -	rssi = be32_to_cpu(info->rssi); -	snr = be32_to_cpu(info->snr); -	noise = be32_to_cpu(info->noise); -  	low = vif->cqm_rssi_low;  	high = vif->cqm_rssi_high;  	last = vif->cqm_rssi_last; @@ -7763,6 +7886,7 @@ static bool brmcf_use_iso3166_ccode_fallback(struct brcmf_pub *drvr)  	switch (drvr->bus_if->chip) {  	case BRCM_CC_43430_CHIP_ID:  	case BRCM_CC_4345_CHIP_ID: +	case BRCM_CC_4356_CHIP_ID:  	case BRCM_CC_43602_CHIP_ID:  		return true;  	default: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 8073f31be27d..9f9bf08a70bb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -212,8 +212,9 @@ struct sbsocramregs {  #define	ARMCR4_TCBANB_MASK	0xf  #define	ARMCR4_TCBANB_SHIFT	0 -#define	ARMCR4_BSZ_MASK		0x3f +#define	ARMCR4_BSZ_MASK		0x7f  #define	ARMCR4_BSZ_MULT		8192 +#define	ARMCR4_BLK_1K_MASK	0x200  struct brcmf_core_priv {  	struct brcmf_core pub; @@ -684,6 +685,7 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)  	u32 nbb;  	u32 totb;  	u32 bxinfo; +	u32 blksize;  	u32 idx;  	corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP); @@ -695,7 +697,11 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)  	for (idx = 0; idx < totb; idx++) {  		brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx);  		bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO); -		memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; +		blksize = ARMCR4_BSZ_MULT; +		if (bxinfo & ARMCR4_BLK_1K_MASK) +			blksize >>= 3; + +		memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * blksize;  	}  	return memsize; @@ -737,6 +743,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)  		return 0x170000;  	case BRCM_CC_4378_CHIP_ID:  		return 0x352000; +	case BRCM_CC_4387_CHIP_ID: +		return 0x740000;  	default:  		brcmf_err("unknown chip: %s\n", ci->pub.name);  		break; @@ -1292,15 +1300,18 @@ static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip)  static inline void  brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip)  { +	int i;  	struct brcmf_core *core;  	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); -	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); -	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | -				   D11_BCMA_IOCTL_PHYCLOCKEN, -			     D11_BCMA_IOCTL_PHYCLOCKEN, -			     D11_BCMA_IOCTL_PHYCLOCKEN); +	/* Disable the cores only and let the firmware enable them. +	 * Releasing reset ourselves breaks BCM4387 in weird ways. +	 */ +	for (i = 0; (core = brcmf_chip_get_d11core(&chip->pub, i)); i++) +		brcmf_chip_coredisable(core, D11_BCMA_IOCTL_PHYRESET | +				       D11_BCMA_IOCTL_PHYCLOCKEN, +				       D11_BCMA_IOCTL_PHYCLOCKEN);  }  static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index f235beaddddb..a194b0e68eb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -101,7 +101,7 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)  static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,  			    struct brcmf_dload_data_le *dload_buf, -			    u32 len) +			    u32 len, const char *var)  {  	s32 err; @@ -111,18 +111,18 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,  	dload_buf->len = cpu_to_le32(len);  	dload_buf->crc = cpu_to_le32(0); -	err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, +	err = brcmf_fil_iovar_data_set(ifp, var, dload_buf,  				       struct_size(dload_buf, data, len));  	return err;  } -static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) +static int brcmf_c_download_blob(struct brcmf_if *ifp, +				 const void *data, size_t size, +				 const char *loadvar, const char *statvar)  {  	struct brcmf_pub *drvr = ifp->drvr; -	struct brcmf_bus *bus = drvr->bus_if;  	struct brcmf_dload_data_le *chunk_buf; -	const struct firmware *clm = NULL;  	u32 chunk_len;  	u32 datalen;  	u32 cumulative_len; @@ -132,21 +132,14 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)  	brcmf_dbg(TRACE, "Enter\n"); -	err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM); -	if (err || !clm) { -		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", -			   err); -		return 0; -	} -  	chunk_buf = kzalloc(struct_size(chunk_buf, data, MAX_CHUNK_LEN),  			    GFP_KERNEL);  	if (!chunk_buf) {  		err = -ENOMEM; -		goto done; +		return -ENOMEM;  	} -	datalen = clm->size; +	datalen = size;  	cumulative_len = 0;  	do {  		if (datalen > MAX_CHUNK_LEN) { @@ -155,9 +148,10 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)  			chunk_len = datalen;  			dl_flag |= DL_END;  		} -		memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len); +		memcpy(chunk_buf->data, data + cumulative_len, chunk_len); -		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len); +		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len, +				       loadvar);  		dl_flag &= ~DL_BEGIN; @@ -166,20 +160,64 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)  	} while ((datalen > 0) && (err == 0));  	if (err) { -		bphy_err(drvr, "clmload (%zu byte file) failed (%d)\n", -			 clm->size, err); -		/* Retrieve clmload_status and print */ -		err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status); +		bphy_err(drvr, "%s (%zu byte file) failed (%d)\n", +			 loadvar, size, err); +		/* Retrieve status and print */ +		err = brcmf_fil_iovar_int_get(ifp, statvar, &status);  		if (err) -			bphy_err(drvr, "get clmload_status failed (%d)\n", err); +			bphy_err(drvr, "get %s failed (%d)\n", statvar, err);  		else -			brcmf_dbg(INFO, "clmload_status=%d\n", status); +			brcmf_dbg(INFO, "%s=%d\n", statvar, status);  		err = -EIO;  	}  	kfree(chunk_buf); -done: -	release_firmware(clm); +	return err; +} + +static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	struct brcmf_bus *bus = drvr->bus_if; +	const struct firmware *fw = NULL; +	s32 err; + +	brcmf_dbg(TRACE, "Enter\n"); + +	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM); +	if (err || !fw) { +		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", +			   err); +		return 0; +	} + +	err = brcmf_c_download_blob(ifp, fw->data, fw->size, +				    "clmload", "clmload_status"); + +	release_firmware(fw); +	return err; +} + +static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	struct brcmf_bus *bus = drvr->bus_if; +	const struct firmware *fw = NULL; +	s32 err; + +	brcmf_dbg(TRACE, "Enter\n"); + +	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP); +	if (err || !fw) { +		brcmf_info("no txcap_blob available (err=%d)\n", err); +		return 0; +	} + +	brcmf_info("TxCap blob found, loading\n"); +	err = brcmf_c_download_blob(ifp, fw->data, fw->size, +				    "txcapload", "txcapload_status"); + +	release_firmware(fw);  	return err;  } @@ -208,6 +246,23 @@ static const u8 brcmf_default_mac_address[ETH_ALEN] = {  	0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38  }; +static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	struct brcmf_mp_device *settings = drvr->settings; +	s32 err; + +	brcmf_dbg(TRACE, "Enter\n"); + +	if (!settings->cal_blob || !settings->cal_size) +		return 0; + +	brcmf_info("Calibration blob provided by platform, loading\n"); +	err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size, +				    "calload", "calload_status"); +	return err; +} +  int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  {  	struct brcmf_pub *drvr = ifp->drvr; @@ -291,6 +346,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  		goto done;  	} +	/* Do TxCap downloading, if needed */ +	err = brcmf_c_process_txcap_blob(ifp); +	if (err < 0) { +		bphy_err(drvr, "download TxCap blob file failed, %d\n", err); +		goto done; +	} + +	/* Download external calibration blob, if available */ +	err = brcmf_c_process_cal_blob(ifp); +	if (err < 0) { +		bphy_err(drvr, "download calibration blob file failed, %d\n", err); +		goto done; +	} +  	/* query for 'ver' to get version info from firmware */  	memset(buf, 0, sizeof(buf));  	err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); @@ -487,6 +556,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,  		/* No platform data for this device, try OF and DMI data */  		brcmf_dmi_probe(settings, chip, chiprev);  		brcmf_of_probe(dev, bus_type, settings); +		brcmf_acpi_probe(dev, bus_type, settings);  	}  	return settings;  } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index aa25abffcc7d..2be2986d2110 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -54,6 +54,8 @@ struct brcmf_mp_device {  	const char	*board_type;  	unsigned char	mac[ETH_ALEN];  	const char	*antenna_sku; +	const void	*cal_blob; +	int		cal_size;  	union {  		struct brcmfmac_sdio_pd sdio;  	} bus; @@ -77,6 +79,15 @@ static inline void  brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}  #endif +#ifdef CONFIG_ACPI +void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type, +		      struct brcmf_mp_device *settings); +#else +static inline void brcmf_acpi_probe(struct device *dev, +				    enum brcmf_bus_type bus_type, +				    struct brcmf_mp_device *settings) {} +#endif +  u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);  u8 brcmf_map_prio_to_aci(void *cfg, u8 prio); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 10bac865d724..6d10c9efbe93 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -126,6 +126,53 @@ static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv)  	drv->feat_flags |= feat_flags;  } +struct brcmf_feat_wlcfeat { +	u16 min_ver_major; +	u16 min_ver_minor; +	u32 feat_flags; +}; + +static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = { +	{ 12, 0, BIT(BRCMF_FEAT_PMKID_V2) }, +	{ 13, 0, BIT(BRCMF_FEAT_PMKID_V3) }, +}; + +static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) +{ +	struct brcmf_if *ifp = brcmf_get_ifp(drv, 0); +	const struct brcmf_feat_wlcfeat *e; +	struct brcmf_wlc_version_le ver; +	u32 feat_flags = 0; +	int i, err, major, minor; + +	err = brcmf_fil_iovar_data_get(ifp, "wlc_ver", &ver, sizeof(ver)); +	if (err) +		return; + +	major = le16_to_cpu(ver.wlc_ver_major); +	minor = le16_to_cpu(ver.wlc_ver_minor); + +	brcmf_dbg(INFO, "WLC version: %d.%d\n", major, minor); + +	for (i = 0; i < ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) { +		e = &brcmf_feat_wlcfeat_map[i]; +		if (major > e->min_ver_major || +		    (major == e->min_ver_major && +		     minor >= e->min_ver_minor)) { +			feat_flags |= e->feat_flags; +		} +	} + +	if (!feat_flags) +		return; + +	for (i = 0; i < BRCMF_FEAT_LAST; i++) +		if (feat_flags & BIT(i)) +			brcmf_dbg(INFO, "enabling firmware feature: %s\n", +				  brcmf_feat_names[i]); +	drv->feat_flags |= feat_flags; +} +  /**   * brcmf_feat_iovar_int_get() - determine feature through iovar query.   * @@ -290,6 +337,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)  		ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);  	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); +	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver");  	if (drvr->settings->feature_disable) {  		brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", @@ -298,6 +346,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)  		ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;  	} +	brcmf_feat_wlc_version_overrides(drvr);  	brcmf_feat_firmware_overrides(drvr);  	/* set chip related quirks */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index f1b086a69d73..7f4f0b3e4a7b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -30,6 +30,7 @@   * SAE: simultaneous authentication of equals   * FWAUTH: Firmware authenticator   * DUMP_OBSS: Firmware has capable to dump obss info to support ACS + * SCAN_V2: Version 2 scan params   */  #define BRCMF_FEAT_LIST \  	BRCMF_FEAT_DEF(MBSS) \ @@ -53,7 +54,10 @@  	BRCMF_FEAT_DEF(DOT11H) \  	BRCMF_FEAT_DEF(SAE) \  	BRCMF_FEAT_DEF(FWAUTH) \ -	BRCMF_FEAT_DEF(DUMP_OBSS) +	BRCMF_FEAT_DEF(DUMP_OBSS) \ +	BRCMF_FEAT_DEF(SCAN_V2) \ +	BRCMF_FEAT_DEF(PMKID_V2) \ +	BRCMF_FEAT_DEF(PMKID_V3)  /*   * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 04e1beedfd81..792adaf880b4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -48,6 +48,10 @@  /* size of brcmf_scan_params not including variable length array */  #define BRCMF_SCAN_PARAMS_FIXED_SIZE	64 +#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE	72 + +/* version of brcmf_scan_params structure */ +#define BRCMF_SCAN_PARAMS_VERSION_V2	2  /* masks for channel and ssid count */  #define BRCMF_SCAN_PARAMS_COUNT_MASK	0x0000ffff @@ -67,6 +71,7 @@  #define BRCMF_PRIMARY_KEY		(1 << 1)  #define DOT11_BSSTYPE_ANY		2  #define BRCMF_ESCAN_REQ_VERSION		1 +#define BRCMF_ESCAN_REQ_VERSION_V2	2  #define BRCMF_MAXRATES_IN_SET		16	/* max # of rates in rateset */ @@ -169,6 +174,10 @@  #define BRCMF_HE_CAP_MCS_MAP_NSS_MAX	8 +#define BRCMF_PMKSA_VER_2		2 +#define BRCMF_PMKSA_VER_3		3 +#define BRCMF_PMKSA_NO_EXPIRY		0xffffffff +  /* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each   * ioctl. It is relatively small because firmware has small maximum size input   * playload restriction for ioctls. @@ -350,6 +359,12 @@ struct brcmf_ssid_le {  	unsigned char SSID[IEEE80211_MAX_SSID_LEN];  }; +/* Alternate SSID structure used in some places... */ +struct brcmf_ssid8_le { +	u8 SSID_len; +	unsigned char SSID[IEEE80211_MAX_SSID_LEN]; +}; +  struct brcmf_scan_params_le {  	struct brcmf_ssid_le ssid_le;	/* default: {0, ""} */  	u8 bssid[ETH_ALEN];	/* default: bcast */ @@ -386,6 +401,45 @@ struct brcmf_scan_params_le {  	__le16 channel_list[1];	/* list of chanspecs */  }; +struct brcmf_scan_params_v2_le { +	__le16 version;		/* structure version */ +	__le16 length;		/* structure length */ +	struct brcmf_ssid_le ssid_le;	/* default: {0, ""} */ +	u8 bssid[ETH_ALEN];	/* default: bcast */ +	s8 bss_type;		/* default: any, +				 * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT +				 */ +	u8 pad; +	__le32 scan_type;	/* flags, 0 use default */ +	__le32 nprobes;		/* -1 use default, number of probes per channel */ +	__le32 active_time;	/* -1 use default, dwell time per channel for +				 * active scanning +				 */ +	__le32 passive_time;	/* -1 use default, dwell time per channel +				 * for passive scanning +				 */ +	__le32 home_time;	/* -1 use default, dwell time for the +				 * home channel between channel scans +				 */ +	__le32 channel_num;	/* count of channels and ssids that follow +				 * +				 * low half is count of channels in +				 * channel_list, 0 means default (use all +				 * available channels) +				 * +				 * high half is entries in struct brcmf_ssid +				 * array that follows channel_list, aligned for +				 * s32 (4 bytes) meaning an odd channel count +				 * implies a 2-byte pad between end of +				 * channel_list and first ssid +				 * +				 * if ssid count is zero, single ssid in the +				 * fixed parameter portion is assumed, otherwise +				 * ssid in the fixed portion is ignored +				 */ +	__le16 channel_list[1];	/* list of chanspecs */ +}; +  struct brcmf_scan_results {  	u32 buflen;  	u32 version; @@ -397,7 +451,10 @@ struct brcmf_escan_params_le {  	__le32 version;  	__le16 action;  	__le16 sync_id; -	struct brcmf_scan_params_le params_le; +	union { +		struct brcmf_scan_params_le params_le; +		struct brcmf_scan_params_v2_le params_v2_le; +	};  };  struct brcmf_escan_result_le { @@ -742,6 +799,31 @@ struct brcmf_rev_info_le {  };  /** + * struct brcmf_wlc_version_le - firmware revision info. + * + * @version: structure version. + * @length: structure length. + * @epi_ver_major: EPI major version + * @epi_ver_minor: EPI minor version + * @epi_ver_rc: EPI rc version + * @epi_ver_incr: EPI increment version + * @wlc_ver_major: WLC major version + * @wlc_ver_minor: WLC minor version + */ +struct brcmf_wlc_version_le { +	__le16 version; +	__le16 length; + +	__le16 epi_ver_major; +	__le16 epi_ver_minor; +	__le16 epi_ver_rc; +	__le16 epi_ver_incr; + +	__le16 wlc_ver_major; +	__le16 wlc_ver_minor; +}; + +/**   * struct brcmf_assoclist_le - request assoc list.   *   * @count: indicates number of stations. @@ -804,6 +886,51 @@ struct brcmf_pmksa {  };  /** + * struct brcmf_pmksa_v2 - PMK Security Association + * + * @length: Length of the structure. + * @bssid: The AP's BSSID. + * @pmkid: The PMK ID. + * @pmk: PMK material for FILS key derivation. + * @pmk_len: Length of PMK data. + * @ssid: The AP's SSID. + * @fils_cache_id: FILS cache identifier + */ +struct brcmf_pmksa_v2 { +	__le16 length; +	u8 bssid[ETH_ALEN]; +	u8 pmkid[WLAN_PMKID_LEN]; +	u8 pmk[WLAN_PMK_LEN_SUITE_B_192]; +	__le16 pmk_len; +	struct brcmf_ssid8_le ssid; +	u16 fils_cache_id; +}; + +/** + * struct brcmf_pmksa_v3 - PMK Security Association + * + * @bssid: The AP's BSSID. + * @pmkid: The PMK ID. + * @pmkid_len: The length of the PMK ID. + * @pmk: PMK material for FILS key derivation. + * @pmk_len: Length of PMK data. + * @fils_cache_id: FILS cache identifier + * @ssid: The AP's SSID. + * @time_left: Remaining time until expiry. 0 = expired, ~0 = no expiry. + */ +struct brcmf_pmksa_v3 { +	u8 bssid[ETH_ALEN]; +	u8 pmkid[WLAN_PMKID_LEN]; +	u8 pmkid_len; +	u8 pmk[WLAN_PMK_LEN_SUITE_B_192]; +	u8 pmk_len; +	__le16 fils_cache_id; +	u8 pad; +	struct brcmf_ssid8_le ssid; +	__le32 time_left; +}; + +/**   * struct brcmf_pmk_list_le - List of pmksa's.   *   * @npmk: Number of pmksa's. @@ -815,6 +942,34 @@ struct brcmf_pmk_list_le {  };  /** + * struct brcmf_pmk_list_v2_le - List of pmksa's. + * + * @version: Request version. + * @length: Length of this structure. + * @pmk: PMK SA information. + */ +struct brcmf_pmk_list_v2_le { +	__le16 version; +	__le16 length; +	struct brcmf_pmksa_v2 pmk[BRCMF_MAXPMKID]; +}; + +/** + * struct brcmf_pmk_op_v3_le - Operation on PMKSA list. + * + * @version: Request version. + * @length: Length of this structure. + * @pmk: PMK SA information. + */ +struct brcmf_pmk_op_v3_le { +	__le16 version; +	__le16 length; +	__le16 count; +	__le16 pad; +	struct brcmf_pmksa_v3 pmk[BRCMF_MAXPMKID]; +}; + +/**   * struct brcmf_pno_param_le - PNO scan configuration parameters   *   * @version: PNO parameters version. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index fdd0c9abc1a1..e406e11481a6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -86,6 +86,13 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,  	if (!of_property_read_string(np, "apple,antenna-sku", &prop))  		settings->antenna_sku = prop; +	/* The WLAN calibration blob is normally stored in SROM, but Apple +	 * ARM64 platforms pass it via the DT instead. +	 */ +	prop = of_get_property(np, "brcm,cal-blob", &settings->cal_size); +	if (prop && settings->cal_size) +		settings->cal_blob = prop; +  	/* Set board-type to the first string of the machine compatible prop */  	root = of_find_node_by_path("/");  	if (root && err) { @@ -122,7 +129,7 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,  		sdio->drive_strength = val;  	/* make sure there are interrupts defined in the node */ -	if (!of_find_property(np, "interrupts", NULL)) +	if (!of_property_present(np, "interrupts"))  		return;  	irq = irq_of_parse_and_map(np, 0); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index a9b9b2dc62d4..80220685f5e4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -15,6 +15,7 @@  #include <linux/sched/signal.h>  #include <linux/kthread.h>  #include <linux/io.h> +#include <linux/random.h>  #include <asm/unaligned.h>  #include <soc.h> @@ -57,6 +58,7 @@ BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie");  BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie");  BRCMF_FW_DEF(4358, "brcmfmac4358-pcie");  BRCMF_FW_DEF(4359, "brcmfmac4359-pcie"); +BRCMF_FW_DEF(4359C, "brcmfmac4359c-pcie");  BRCMF_FW_CLM_DEF(4364B2, "brcmfmac4364b2-pcie");  BRCMF_FW_CLM_DEF(4364B3, "brcmfmac4364b3-pcie");  BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie"); @@ -66,6 +68,8 @@ BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");  BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");  BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie");  BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); +BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); +BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie");  /* firmware config files */  MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); @@ -74,6 +78,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");  /* per-board firmware binaries */  MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin");  MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob"); +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txcap_blob");  static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {  	BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), @@ -88,7 +93,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {  	BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570),  	BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570),  	BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), -	BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), +	BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0x000001FF, 4359), +	BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFE00, 4359C),  	BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0x0000000F, 4364B2), /* 3 */  	BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0xFFFFFFF0, 4364B3), /* 4 */  	BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), @@ -99,7 +105,9 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {  	BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C),  	BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),  	BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* revision ID 4 */ -	BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* revision ID 3 */ +	BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */ +	BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */ +	BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* revision ID 7 */  };  #define BRCMF_PCIE_FW_UP_TIMEOUT		5000 /* msec */ @@ -326,7 +334,9 @@ struct brcmf_pciedev_info {  	char fw_name[BRCMF_FW_NAME_LEN];  	char nvram_name[BRCMF_FW_NAME_LEN];  	char clm_name[BRCMF_FW_NAME_LEN]; +	char txcap_name[BRCMF_FW_NAME_LEN];  	const struct firmware *clm_fw; +	const struct firmware *txcap_fw;  	const struct brcmf_pcie_reginfo *reginfo;  	void __iomem *regs;  	void __iomem *tcm; @@ -1517,6 +1527,10 @@ static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,  		*fw = devinfo->clm_fw;  		devinfo->clm_fw = NULL;  		break; +	case BRCMF_BLOB_TXCAP: +		*fw = devinfo->txcap_fw; +		devinfo->txcap_fw = NULL; +		break;  	default:  		return -ENOENT;  	} @@ -1653,6 +1667,13 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,  	return 0;  } +struct brcmf_random_seed_footer { +	__le32 length; +	__le32 magic; +}; + +#define BRCMF_RANDOM_SEED_MAGIC		0xfeedc0de +#define BRCMF_RANDOM_SEED_LENGTH	0x100  static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,  					const struct firmware *fw, void *nvram, @@ -1689,6 +1710,30 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,  			  nvram_len;  		memcpy_toio(devinfo->tcm + address, nvram, nvram_len);  		brcmf_fw_nvram_free(nvram); + +		if (devinfo->otp.valid) { +			size_t rand_len = BRCMF_RANDOM_SEED_LENGTH; +			struct brcmf_random_seed_footer footer = { +				.length = cpu_to_le32(rand_len), +				.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC), +			}; +			void *randbuf; + +			/* Some Apple chips/firmwares expect a buffer of random +			 * data to be present before NVRAM +			 */ +			brcmf_dbg(PCIE, "Download random seed\n"); + +			address -= sizeof(footer); +			memcpy_toio(devinfo->tcm + address, &footer, +				    sizeof(footer)); + +			address -= rand_len; +			randbuf = kzalloc(rand_len, GFP_KERNEL); +			get_random_bytes(randbuf, rand_len); +			memcpy_toio(devinfo->tcm + address, randbuf, rand_len); +			kfree(randbuf); +		}  	} else {  		brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",  			  devinfo->nvram_name); @@ -2016,6 +2061,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)  		base = 0x1120;  		words = 0x170;  		break; +	case BRCM_CC_4387_CHIP_ID: +		coreid = BCMA_CORE_GCI; +		base = 0x113c; +		words = 0x170; +		break;  	default:  		/* OTP not supported on this chip */  		return 0; @@ -2073,6 +2123,7 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)  #define BRCMF_PCIE_FW_CODE	0  #define BRCMF_PCIE_FW_NVRAM	1  #define BRCMF_PCIE_FW_CLM	2 +#define BRCMF_PCIE_FW_TXCAP	3  static void brcmf_pcie_setup(struct device *dev, int ret,  			     struct brcmf_fw_request *fwreq) @@ -2099,6 +2150,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,  	nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;  	nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;  	devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary; +	devinfo->txcap_fw = fwreq->items[BRCMF_PCIE_FW_TXCAP].binary;  	kfree(fwreq);  	ret = brcmf_chip_get_raminfo(devinfo->ci); @@ -2180,6 +2232,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)  		{ ".bin", devinfo->fw_name },  		{ ".txt", devinfo->nvram_name },  		{ ".clm_blob", devinfo->clm_name }, +		{ ".txcap_blob", devinfo->txcap_name },  	};  	fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, @@ -2194,6 +2247,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)  	fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;  	fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;  	fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; +	fwreq->items[BRCMF_PCIE_FW_TXCAP].type = BRCMF_FW_TYPE_BINARY; +	fwreq->items[BRCMF_PCIE_FW_TXCAP].flags = BRCMF_FW_REQF_OPTIONAL;  	/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */  	fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;  	fwreq->bus_nr = devinfo->pdev->bus->number; @@ -2339,6 +2394,9 @@ static void brcmf_pcie_debugfs_create(struct device *dev)  }  #endif +/* Forward declaration for pci_match_id() call */ +static const struct pci_device_id brcmf_pcie_devid_table[]; +  static int  brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  { @@ -2349,6 +2407,14 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	struct brcmf_core *core;  	struct brcmf_bus *bus; +	if (!id) { +		id = pci_match_id(brcmf_pcie_devid_table, pdev); +		if (!id) { +			pci_err(pdev, "Error could not find pci_device_id for %x:%x\n", pdev->vendor, pdev->device); +			return -ENODEV; +		} +	} +  	brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);  	ret = -ENOMEM; @@ -2491,6 +2557,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)  	brcmf_pcie_reset_device(devinfo);  	brcmf_pcie_release_resource(devinfo);  	release_firmware(devinfo->clm_fw); +	release_firmware(devinfo->txcap_fw);  	if (devinfo->ci)  		brcmf_chip_detach(devinfo->ci); @@ -2630,6 +2697,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = {  	BRCMF_PCIE_DEVICE(BRCM_PCIE_43596_DEVICE_ID, CYW),  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC),  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC), +	BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC),  	{ /* end: all zeroes */ }  }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index b76d34d36bde..0d18ed15b403 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -188,6 +188,8 @@ struct brcmf_sdio_dev {  	char nvram_name[BRCMF_FW_NAME_LEN];  	char clm_name[BRCMF_FW_NAME_LEN];  	bool wowl_enabled; +	bool func1_power_manageable; +	bool func2_power_manageable;  	enum brcmf_sdiod_state state;  	struct brcmf_sdiod_freezer *freezer;  	const struct firmware *clm_fw; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 246843aeb696..2178675ae1a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1331,6 +1331,9 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)  	brcmf_usb_detach(devinfo);  } +/* Forward declaration for usb_match_id() call */ +static const struct usb_device_id brcmf_usb_devid_table[]; +  static int  brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  { @@ -1342,6 +1345,14 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  	u32 num_of_eps;  	u8 endpoint_num, ep; +	if (!id) { +		id = usb_match_id(intf, brcmf_usb_devid_table); +		if (!id) { +			dev_err(&intf->dev, "Error could not find matching usb_device_id\n"); +			return -ENODEV; +		} +	} +  	brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);  	devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c index 2631eb7569eb..e24228e60027 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c @@ -845,7 +845,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,  	u16 seq, start_seq = 0, bindex, index, mcl;  	u8 mcs = 0;  	bool ba_recd = false, ack_recd = false; -	u8 suc_mpdu = 0, tot_mpdu = 0; +	u8 tot_mpdu = 0;  	uint supr_status;  	bool retry = true;  	u16 mimoantsel = 0; @@ -975,7 +975,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,  				ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,  							    p);  				ack_recd = true; -				suc_mpdu++;  			}  		}  		/* either retransmit or send bar if ack not recd */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c index 9540a05247c2..89c8829528c2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c @@ -1,6 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  #include <net/mac80211.h>  #include <linux/bcma/bcma_driver_chipcommon.h> +#include <linux/gpio.h>  #include <linux/gpio/driver.h>  #include <linux/gpio/machine.h>  #include <linux/gpio/consumer.h> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index a8333e6adbda..0bd4e679a359 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1048,7 +1048,6 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)  	struct brcms_info *wl = hw->priv;  	struct brcms_c_info *wlc = wl->wlc;  	struct ieee80211_supported_band *band; -	int has_5g = 0;  	u16 phy_type;  	hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL; @@ -1070,7 +1069,6 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)  	/* Assume all bands use the same phy.  True for 11n devices. */  	if (wl->pub->_nbands > 1) { -		has_5g++;  		if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {  			band = &wlc->bandstate[BAND_5G_INDEX]->band;  			*band = brcms_band_5GHz_nphy_template; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 896615f57952..44684bf1b9ac 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -54,6 +54,7 @@  #define BRCM_CC_4371_CHIP_ID		0x4371  #define BRCM_CC_4377_CHIP_ID		0x4377  #define BRCM_CC_4378_CHIP_ID		0x4378 +#define BRCM_CC_4387_CHIP_ID		0x4387  #define CY_CC_4373_CHIP_ID		0x4373  #define CY_CC_43012_CHIP_ID		43012  #define CY_CC_43439_CHIP_ID		43439 @@ -95,6 +96,7 @@  #define BRCM_PCIE_43596_DEVICE_ID	0x4415  #define BRCM_PCIE_4377_DEVICE_ID	0x4488  #define BRCM_PCIE_4378_DEVICE_ID	0x4425 +#define BRCM_PCIE_4387_DEVICE_ID	0x4433  /* brcmsmac IDs */  #define BCM4313_D11N2G_ID	0x4727	/* 4313 802.11n 2.4G device */  |