Commit 2af560e5 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'wireless-next-2023-03-10' of...

Merge tag 'wireless-next-2023-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
wireless-next patches for 6.4

Major changes:

cfg80211
 * 6 GHz improvements
 * HW timestamping support
 * support for randomized auth/deauth TA for PASN privacy
   (also for mac80211)

mac80211
 * radiotap TLV and EHT support for the iwlwifi sniffer
 * HW timestamping support
 * per-link debugfs for multi-link

brcmfmac
 * support for Apple (M1 Pro/Max) devices

iwlwifi
 * support for a few new devices
 * EHT sniffer support

rtw88
 * better support for some SDIO devices
   (e.g. MAC address from efuse)

rtw89
 * HW scan support for 8852b
 * better support for 6 GHz scanning

* tag 'wireless-next-2023-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (84 commits)
  wifi: iwlwifi: mvm: fix EOF bit reporting
  wifi: iwlwifi: Do not include radiotap EHT user info if not needed
  wifi: iwlwifi: mvm: add EHT RU allocation to radiotap
  wifi: iwlwifi: Update logs for yoyo reset sw changes
  wifi: iwlwifi: mvm: clean up duplicated defines
  wifi: iwlwifi: rs-fw: break out for unsupported bandwidth
  wifi: iwlwifi: Add support for B step of BnJ-Fm4
  wifi: iwlwifi: mvm: make flush code a bit clearer
  wifi: iwlwifi: mvm: avoid UB shift of snif_queue
  wifi: iwlwifi: mvm: add primary 80 known for EHT radiotap
  wifi: iwlwifi: mvm: parse FW frame metadata for EHT sniffer mode
  wifi: iwlwifi: mvm: decode USIG_B1_B7 RU to nl80211 RU width
  wifi: iwlwifi: mvm: rename define to generic name
  wifi: iwlwifi: mvm: allow Microsoft to use TAS
  wifi: iwlwifi: mvm: add all EHT based on data0 info from HW
  wifi: iwlwifi: mvm: add EHT radiotap info based on rate_n_flags
  wifi: iwlwifi: mvm: add an helper function radiotap TLVs
  wifi: radiotap: separate vendor TLV into header/content
  wifi: iwlwifi: reduce verbosity of some logging events
  wifi: iwlwifi: Adding the code to get RF name for MsP device
  ...
====================

Link: https://lore.kernel.org/r/20230310120159.36518-1-johannes@sipsolutions.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 127cd685 da118544
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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/
+51 −0
Original line number Diff line number Diff line
// 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");
	}
}
+1 −0
Original line number Diff line number Diff line
@@ -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;
+221 −103
Original line number Diff line number Diff line
@@ -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(&params_le->ssid_le, &params_v2_le->ssid_le,
	       sizeof(params_le->ssid_le));
	memcpy(&params_le->bssid, &params_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(&params_le->channel_list[0],
	       &params_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(&params_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(&params_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, &params_v2_le, NULL);

		/* E-Scan (or anyother type) can be aborted by SCAN */
		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
			err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
					     &params_le, sizeof(params_le));
						     &params_v2_le,
						     sizeof(params_v2_le));
		} else {
			struct brcmf_scan_params_le params_le;

			brcmf_scan_params_v2_to_v1(&params_v2_le, &params_le);
			err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
						     &params_le,
						     sizeof(params_le));
		}

		if (err)
			bphy_err(drvr, "Scan abort failed\n");
	}
@@ -1295,83 +1420,13 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
	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(&params_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, &params->params_le, request);
	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
	brcmf_escan_prep(cfg, &params->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(&params->params_v2_le, &params_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;

	/* 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]);
	memset(&pmk, 0, sizeof(pmk));

	/* 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 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
	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);

@@ -6489,17 +6605,19 @@ 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)) {
		brcmf_err("insufficient RSSI event data\n");
		return 0;
	}

	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;
	}

	low = vif->cqm_rssi_low;
	high = vif->cqm_rssi_high;
+18 −7
Original line number Diff line number Diff line
@@ -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,13 +1300,16 @@ 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,
	/* 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);
}
Loading