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

Commit 7c5556de authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'wireless-drivers-next-for-davem-2017-11-11' of...

Merge tag 'wireless-drivers-next-for-davem-2017-11-11' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next



Kalle Valo says:

====================
wireless-drivers-next patches for 4.15

Last minute patches before the merge window. Not really anything
special standing out, mostly fixes or cleanup and some minor new
features.

Major changes:

iwlwifi

* some new PCI IDs
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39b17521 fdd0bd88
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ struct brcmf_bus_dcmd {
 * @wowl_config: specify if dongle is configured for wowl when going to suspend
 * @get_ramsize: obtain size of device memory.
 * @get_memdump: obtain device memory dump in provided buffer.
 * @get_fwname: obtain firmware name.
 *
 * This structure provides an abstract interface towards the
 * bus specific driver. For control messages to common driver
@@ -87,6 +88,8 @@ struct brcmf_bus_ops {
	void (*wowl_config)(struct device *dev, bool enabled);
	size_t (*get_ramsize)(struct device *dev);
	int (*get_memdump)(struct device *dev, void *data, size_t len);
	int (*get_fwname)(struct device *dev, uint chip, uint chiprev,
			  unsigned char *fw_name);
};


@@ -224,6 +227,13 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
	return bus->ops->get_memdump(bus->dev, data, len);
}

static inline
int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
			 unsigned char *fw_name)
{
	return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
}

/*
 * interface functions from common layer
 */
+25 −137
Original line number Diff line number Diff line
@@ -472,47 +472,6 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
	return err;
}

static s32
brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
{
	s32 err;
	u32 mode;

	if (enable)
		mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
	else
		mode = 0;

	/* Try to set and enable ARP offload feature, this may fail, then it  */
	/* is simply not supported and err 0 will be returned                 */
	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
	if (err) {
		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
			  mode, err);
		err = 0;
	} else {
		err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
		if (err) {
			brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
				  enable, err);
			err = 0;
		} else
			brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
				  enable, mode);
	}

	err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
	if (err) {
		brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
			  enable, err);
		err = 0;
	} else
		brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
			  enable, mode);

	return err;
}

static void
brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
{
@@ -1084,7 +1043,6 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
{
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	s32 err;
	u32 passive_scan;
	struct brcmf_scan_results *results;
	struct escan_info *escan = &cfg->escan_info;

@@ -1092,13 +1050,7 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
	escan->ifp = ifp;
	escan->wiphy = cfg->wiphy;
	escan->escan_state = WL_ESCAN_STATE_SCANNING;
	passive_scan = cfg->active_scan ? 0 : 1;
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
				    passive_scan);
	if (err) {
		brcmf_err("error (%d)\n", err);
		return err;
	}

	brcmf_scan_config_mpc(ifp, 0);
	results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
	results->version = 0;
@@ -1112,21 +1064,16 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
}

static s32
brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
		     struct cfg80211_scan_request *request,
		     struct cfg80211_ssid *this_ssid)
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
	struct brcmf_if *ifp = vif->ifp;
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct cfg80211_ssid *ssids;
	u32 passive_scan;
	bool escan_req;
	bool spec_scan;
	s32 err;
	struct brcmf_ssid_le ssid_le;
	u32 SSID_len;
	struct brcmf_cfg80211_vif *vif;
	s32 err = 0;

	brcmf_dbg(SCAN, "START ESCAN\n");
	brcmf_dbg(TRACE, "Enter\n");
	vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
	if (!check_vif_up(vif))
		return -EIO;

	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
@@ -1142,8 +1089,8 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
			  cfg->scan_status);
		return -EAGAIN;
	}
	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
		brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
		brcmf_err("Connecting: status (%lu)\n", vif->sme_state);
		return -EAGAIN;
	}

@@ -1151,96 +1098,38 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
	if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
		vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;

	escan_req = false;
	if (request) {
		/* scan bss */
		ssids = request->ssids;
		escan_req = true;
	} else {
		/* scan in ibss */
		/* we don't do escan in ibss */
		ssids = this_ssid;
	}
	brcmf_dbg(SCAN, "START ESCAN\n");

	cfg->scan_request = request;
	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	if (escan_req) {

	cfg->escan_info.run = brcmf_run_escan;
	err = brcmf_p2p_scan_prep(wiphy, request, vif);
	if (err)
		goto scan_out;

		err = brcmf_do_escan(vif->ifp, request);
	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
				    request->ie, request->ie_len);
	if (err)
		goto scan_out;
	} else {
		brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
			  ssids->ssid, ssids->ssid_len);
		memset(&ssid_le, 0, sizeof(ssid_le));
		SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
		ssid_le.SSID_len = cpu_to_le32(0);
		spec_scan = false;
		if (SSID_len) {
			memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
			ssid_le.SSID_len = cpu_to_le32(SSID_len);
			spec_scan = true;
		} else
			brcmf_dbg(SCAN, "Broadcast scan\n");

		passive_scan = cfg->active_scan ? 0 : 1;
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
					    passive_scan);
		if (err) {
			brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
			goto scan_out;
		}
		brcmf_scan_config_mpc(ifp, 0);
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
					     sizeof(ssid_le));
		if (err) {
			if (err == -EBUSY)
				brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
					  ssid_le.SSID);
			else
				brcmf_err("WLC_SCAN error (%d)\n", err);

			brcmf_scan_config_mpc(ifp, 1);
	err = brcmf_do_escan(vif->ifp, request);
	if (err)
		goto scan_out;
		}
	}

	/* Arm scan timeout timer */
	mod_timer(&cfg->escan_timeout, jiffies +
			BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
	mod_timer(&cfg->escan_timeout,
		  jiffies + msecs_to_jiffies(BRCMF_ESCAN_TIMER_INTERVAL_MS));

	return 0;

scan_out:
	brcmf_err("scan error (%d)\n", err);
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	cfg->scan_request = NULL;
	return err;
}

static s32
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
	struct brcmf_cfg80211_vif *vif;
	s32 err = 0;

	brcmf_dbg(TRACE, "Enter\n");
	vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
	if (!check_vif_up(vif))
		return -EIO;

	err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);

	if (err)
		brcmf_err("scan error (%d)\n", err);

	brcmf_dbg(TRACE, "Exit\n");
	return err;
}

static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
{
	s32 err = 0;
@@ -5876,7 +5765,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)

	cfg->scan_request = NULL;
	cfg->pwr_save = true;
	cfg->active_scan = true;	/* we do active scan per default */
	cfg->dongle_up = false;		/* dongle is not up yet */
	err = brcmf_init_priv_mem(cfg);
	if (err)
+0 −2
Original line number Diff line number Diff line
@@ -283,7 +283,6 @@ struct brcmf_cfg80211_wowl {
 * @scan_status: scan activity on the dongle.
 * @pub: common driver information.
 * @channel: current channel.
 * @active_scan: current scan mode.
 * @int_escan_map: bucket map for which internal e-scan is done.
 * @ibss_starter: indicates this sta is ibss starter.
 * @pwr_save: indicate whether dongle to support power save mode.
@@ -316,7 +315,6 @@ struct brcmf_cfg80211_info {
	unsigned long scan_status;
	struct brcmf_pub *pub;
	u32 channel;
	bool active_scan;
	u32 int_escan_map;
	bool ibss_starter;
	bool pwr_save;
+157 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
@@ -28,6 +29,7 @@
#include "tracepoint.h"
#include "common.h"
#include "of.h"
#include "firmware.h"

MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -104,12 +106,140 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
		brcmf_err("Set join_pref error (%d)\n", err);
}

static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
			    struct brcmf_dload_data_le *dload_buf,
			    u32 len)
{
	s32 err;

	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
	dload_buf->flag = cpu_to_le16(flag);
	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
	dload_buf->len = cpu_to_le32(len);
	dload_buf->crc = cpu_to_le32(0);
	len = sizeof(*dload_buf) + len - 1;

	err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, len);

	return err;
}

static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name)
{
	struct brcmf_bus *bus = ifp->drvr->bus_if;
	struct brcmf_rev_info *ri = &ifp->drvr->revinfo;
	u8 fw_name[BRCMF_FW_NAME_LEN];
	u8 *ptr;
	size_t len;
	s32 err;

	memset(fw_name, 0, BRCMF_FW_NAME_LEN);
	err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name);
	if (err) {
		brcmf_err("get firmware name failed (%d)\n", err);
		goto done;
	}

	/* generate CLM blob file name */
	ptr = strrchr(fw_name, '.');
	if (!ptr) {
		err = -ENOENT;
		goto done;
	}

	len = ptr - fw_name + 1;
	if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) {
		err = -E2BIG;
	} else {
		strlcpy(clm_name, fw_name, len);
		strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN);
	}
done:
	return err;
}

static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
{
	struct device *dev = ifp->drvr->bus_if->dev;
	struct brcmf_dload_data_le *chunk_buf;
	const struct firmware *clm = NULL;
	u8 clm_name[BRCMF_FW_NAME_LEN];
	u32 chunk_len;
	u32 datalen;
	u32 cumulative_len;
	u16 dl_flag = DL_BEGIN;
	u32 status;
	s32 err;

	brcmf_dbg(TRACE, "Enter\n");

	memset(clm_name, 0, BRCMF_FW_NAME_LEN);
	err = brcmf_c_get_clm_name(ifp, clm_name);
	if (err) {
		brcmf_err("get CLM blob file name failed (%d)\n", err);
		return err;
	}

	err = request_firmware(&clm, clm_name, dev);
	if (err) {
		if (err == -ENOENT) {
			brcmf_dbg(INFO, "continue with CLM data currently present in firmware\n");
			return 0;
		}
		brcmf_err("request CLM blob file failed (%d)\n", err);
		return err;
	}

	chunk_buf = kzalloc(sizeof(*chunk_buf) + MAX_CHUNK_LEN - 1, GFP_KERNEL);
	if (!chunk_buf) {
		err = -ENOMEM;
		goto done;
	}

	datalen = clm->size;
	cumulative_len = 0;
	do {
		if (datalen > MAX_CHUNK_LEN) {
			chunk_len = MAX_CHUNK_LEN;
		} else {
			chunk_len = datalen;
			dl_flag |= DL_END;
		}
		memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len);

		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len);

		dl_flag &= ~DL_BEGIN;

		cumulative_len += chunk_len;
		datalen -= chunk_len;
	} while ((datalen > 0) && (err == 0));

	if (err) {
		brcmf_err("clmload (%zu byte file) failed (%d); ",
			  clm->size, err);
		/* Retrieve clmload_status and print */
		err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status);
		if (err)
			brcmf_err("get clmload_status failed (%d)\n", err);
		else
			brcmf_dbg(INFO, "clmload_status=%d\n", status);
		err = -EIO;
	}

	kfree(chunk_buf);
done:
	release_firmware(clm);
	return err;
}

int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
	s8 eventmask[BRCMF_EVENTING_MASK_LEN];
	u8 buf[BRCMF_DCMD_SMLEN];
	struct brcmf_rev_info_le revinfo;
	struct brcmf_rev_info *ri;
	char *clmver;
	char *ptr;
	s32 err;

@@ -148,6 +278,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
	}
	ri->result = err;

	/* Do any CLM downloading */
	err = brcmf_c_process_clm_blob(ifp);
	if (err < 0) {
		brcmf_err("download CLM blob file failed, %d\n", err);
		goto done;
	}

	/* query for 'ver' to get version info from firmware */
	memset(buf, 0, sizeof(buf));
	strcpy(buf, "ver");
@@ -167,6 +304,26 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
	ptr = strrchr(buf, ' ') + 1;
	strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));

	/* Query for 'clmver' to get CLM version info from firmware */
	memset(buf, 0, sizeof(buf));
	err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
	if (err) {
		brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
	} else {
		clmver = (char *)buf;
		/* store CLM version for adding it to revinfo debugfs file */
		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));

		/* Replace all newline/linefeed characters with space
		 * character
		 */
		ptr = clmver;
		while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL)
			*ptr = ' ';

		brcmf_dbg(INFO, "CLM version = %s\n", clmver);
	}

	/* set mpc */
	err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
	if (err) {
+40 −0
Original line number Diff line number Diff line
@@ -71,6 +71,43 @@ struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
	return ifp;
}

void brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
{
	s32 err;
	u32 mode;

	if (enable)
		mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
	else
		mode = 0;

	/* Try to set and enable ARP offload feature, this may fail, then it  */
	/* is simply not supported and err 0 will be returned                 */
	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
	if (err) {
		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
			  mode, err);
	} else {
		err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
		if (err) {
			brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
				  enable, err);
		} else {
			brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
				  enable, mode);
		}
	}

	err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
	if (err) {
		brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
			  enable, err);
	} else {
		brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
			  enable, mode);
	}
}

static void _brcmf_set_multicast_list(struct work_struct *work)
{
	struct brcmf_if *ifp;
@@ -134,6 +171,7 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
	if (err < 0)
		brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
			  err);
	brcmf_configure_arp_nd_offload(ifp, !cmd_value);
}

#if IS_ENABLED(CONFIG_IPV6)
@@ -950,6 +988,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
	seq_printf(s, "anarev: %u\n", ri->anarev);
	seq_printf(s, "nvramrev: %08x\n", ri->nvramrev);

	seq_printf(s, "clmver: %s\n", bus_if->drvr->clmver);

	return 0;
}

Loading