xref: /openbmc/linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1daeccac2SArend van Spriel // SPDX-License-Identifier: ISC
205491d2cSKalle Valo /*
305491d2cSKalle Valo  * Copyright (c) 2010 Broadcom Corporation
405491d2cSKalle Valo  */
505491d2cSKalle Valo 
605491d2cSKalle Valo #include <linux/kernel.h>
705491d2cSKalle Valo #include <linux/string.h>
805491d2cSKalle Valo #include <linux/netdevice.h>
95dc3b7b9SFelix Fietkau #include <linux/module.h>
10fdd0bd88SChung-Hsien Hsu #include <linux/firmware.h>
1105491d2cSKalle Valo #include <brcmu_wifi.h>
1205491d2cSKalle Valo #include <brcmu_utils.h>
1305491d2cSKalle Valo #include "core.h"
1405491d2cSKalle Valo #include "bus.h"
1505491d2cSKalle Valo #include "debug.h"
1605491d2cSKalle Valo #include "fwil.h"
1705491d2cSKalle Valo #include "fwil_types.h"
1805491d2cSKalle Valo #include "tracepoint.h"
1905491d2cSKalle Valo #include "common.h"
208ea56be0SHante Meuleman #include "of.h"
21fdd0bd88SChung-Hsien Hsu #include "firmware.h"
22756a2b39SArend Van Spriel #include "chip.h"
2305491d2cSKalle Valo 
24d84d99e0SHante Meuleman MODULE_AUTHOR("Broadcom Corporation");
25d84d99e0SHante Meuleman MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
26d84d99e0SHante Meuleman MODULE_LICENSE("Dual BSD/GPL");
27d84d99e0SHante Meuleman 
2805491d2cSKalle Valo #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40
2905491d2cSKalle Valo #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40
3005491d2cSKalle Valo 
317705ba6fSArend van Spriel /* default boost value for RSSI_DELTA in preferred join selection */
3205491d2cSKalle Valo #define BRCMF_JOIN_PREF_RSSI_BOOST	8
3305491d2cSKalle Valo 
347d34b056SHante Meuleman #define BRCMF_DEFAULT_TXGLOM_SIZE	32  /* max tx frames in glom chain */
357d34b056SHante Meuleman 
367d34b056SHante Meuleman static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
377d34b056SHante Meuleman module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
387d34b056SHante Meuleman MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
397d34b056SHante Meuleman 
407d34b056SHante Meuleman /* Debug level configuration. See debug.h for bits, sysfs modifiable */
417d34b056SHante Meuleman int brcmf_msg_level;
422ef00c53SJoe Perches module_param_named(debug, brcmf_msg_level, int, 0600);
437d34b056SHante Meuleman MODULE_PARM_DESC(debug, "Level of debug output");
447d34b056SHante Meuleman 
457d34b056SHante Meuleman static int brcmf_p2p_enable;
467d34b056SHante Meuleman module_param_named(p2pon, brcmf_p2p_enable, int, 0);
477d34b056SHante Meuleman MODULE_PARM_DESC(p2pon, "Enable legacy p2p management functionality");
487d34b056SHante Meuleman 
497d34b056SHante Meuleman static int brcmf_feature_disable;
507d34b056SHante Meuleman module_param_named(feature_disable, brcmf_feature_disable, int, 0);
517d34b056SHante Meuleman MODULE_PARM_DESC(feature_disable, "Disable features");
527d34b056SHante Meuleman 
537d34b056SHante Meuleman static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
547d34b056SHante Meuleman module_param_string(alternative_fw_path, brcmf_firmware_path,
552ef00c53SJoe Perches 		    BRCMF_FW_ALTPATH_LEN, 0400);
567d34b056SHante Meuleman MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
577d34b056SHante Meuleman 
587d34b056SHante Meuleman static int brcmf_fcmode;
597d34b056SHante Meuleman module_param_named(fcmode, brcmf_fcmode, int, 0);
607d34b056SHante Meuleman MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
617d34b056SHante Meuleman 
627d34b056SHante Meuleman static int brcmf_roamoff;
632ef00c53SJoe Perches module_param_named(roamoff, brcmf_roamoff, int, 0400);
647d34b056SHante Meuleman MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
657d34b056SHante Meuleman 
6612590551SRafał Miłecki static int brcmf_iapp_enable;
6712590551SRafał Miłecki module_param_named(iapp, brcmf_iapp_enable, int, 0);
6812590551SRafał Miłecki MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
6912590551SRafał Miłecki 
708ba83d4dSArend van Spriel #ifdef DEBUG
71e8cd4750SRafał Miłecki /* always succeed brcmf_bus_started() */
728ba83d4dSArend van Spriel static int brcmf_ignore_probe_fail;
738ba83d4dSArend van Spriel module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
748ba83d4dSArend van Spriel MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
758ba83d4dSArend van Spriel #endif
768ba83d4dSArend van Spriel 
774d792895SHante Meuleman static struct brcmfmac_platform_data *brcmfmac_pdata;
787d34b056SHante Meuleman struct brcmf_mp_global_t brcmf_mp_global;
797d34b056SHante Meuleman 
brcmf_c_set_joinpref_default(struct brcmf_if * ifp)807705ba6fSArend van Spriel void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
817705ba6fSArend van Spriel {
82dcb1471bSRafał Miłecki 	struct brcmf_pub *drvr = ifp->drvr;
837705ba6fSArend van Spriel 	struct brcmf_join_pref_params join_pref_params[2];
847705ba6fSArend van Spriel 	int err;
857705ba6fSArend van Spriel 
867705ba6fSArend van Spriel 	/* Setup join_pref to select target by RSSI (boost on 5GHz) */
877705ba6fSArend van Spriel 	join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
887705ba6fSArend van Spriel 	join_pref_params[0].len = 2;
897705ba6fSArend van Spriel 	join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
907705ba6fSArend van Spriel 	join_pref_params[0].band = WLC_BAND_5G;
917705ba6fSArend van Spriel 
927705ba6fSArend van Spriel 	join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
937705ba6fSArend van Spriel 	join_pref_params[1].len = 2;
947705ba6fSArend van Spriel 	join_pref_params[1].rssi_gain = 0;
957705ba6fSArend van Spriel 	join_pref_params[1].band = 0;
967705ba6fSArend van Spriel 	err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
977705ba6fSArend van Spriel 				       sizeof(join_pref_params));
987705ba6fSArend van Spriel 	if (err)
99dcb1471bSRafał Miłecki 		bphy_err(drvr, "Set join_pref error (%d)\n", err);
1007705ba6fSArend van Spriel }
1017705ba6fSArend van Spriel 
brcmf_c_download(struct brcmf_if * ifp,u16 flag,struct brcmf_dload_data_le * dload_buf,u32 len,const char * var)102fdd0bd88SChung-Hsien Hsu static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
103fdd0bd88SChung-Hsien Hsu 			    struct brcmf_dload_data_le *dload_buf,
104dd7e5540SHector Martin 			    u32 len, const char *var)
105fdd0bd88SChung-Hsien Hsu {
106fdd0bd88SChung-Hsien Hsu 	s32 err;
107fdd0bd88SChung-Hsien Hsu 
108fdd0bd88SChung-Hsien Hsu 	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
109fdd0bd88SChung-Hsien Hsu 	dload_buf->flag = cpu_to_le16(flag);
110fdd0bd88SChung-Hsien Hsu 	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
111fdd0bd88SChung-Hsien Hsu 	dload_buf->len = cpu_to_le32(len);
112fdd0bd88SChung-Hsien Hsu 	dload_buf->crc = cpu_to_le32(0);
113fdd0bd88SChung-Hsien Hsu 
114dd7e5540SHector Martin 	err = brcmf_fil_iovar_data_set(ifp, var, dload_buf,
115633a9b6fSGustavo A. R. Silva 				       struct_size(dload_buf, data, len));
116fdd0bd88SChung-Hsien Hsu 
117fdd0bd88SChung-Hsien Hsu 	return err;
118fdd0bd88SChung-Hsien Hsu }
119fdd0bd88SChung-Hsien Hsu 
brcmf_c_download_blob(struct brcmf_if * ifp,const void * data,size_t size,const char * loadvar,const char * statvar)120dd7e5540SHector Martin static int brcmf_c_download_blob(struct brcmf_if *ifp,
121dd7e5540SHector Martin 				 const void *data, size_t size,
122dd7e5540SHector Martin 				 const char *loadvar, const char *statvar)
123fdd0bd88SChung-Hsien Hsu {
124dcb1471bSRafał Miłecki 	struct brcmf_pub *drvr = ifp->drvr;
125fdd0bd88SChung-Hsien Hsu 	struct brcmf_dload_data_le *chunk_buf;
126fdd0bd88SChung-Hsien Hsu 	u32 chunk_len;
127fdd0bd88SChung-Hsien Hsu 	u32 datalen;
128fdd0bd88SChung-Hsien Hsu 	u32 cumulative_len;
129fdd0bd88SChung-Hsien Hsu 	u16 dl_flag = DL_BEGIN;
130fdd0bd88SChung-Hsien Hsu 	u32 status;
131fdd0bd88SChung-Hsien Hsu 	s32 err;
132fdd0bd88SChung-Hsien Hsu 
133fdd0bd88SChung-Hsien Hsu 	brcmf_dbg(TRACE, "Enter\n");
134fdd0bd88SChung-Hsien Hsu 
135633a9b6fSGustavo A. R. Silva 	chunk_buf = kzalloc(struct_size(chunk_buf, data, MAX_CHUNK_LEN),
136633a9b6fSGustavo A. R. Silva 			    GFP_KERNEL);
137fdd0bd88SChung-Hsien Hsu 	if (!chunk_buf) {
138fdd0bd88SChung-Hsien Hsu 		err = -ENOMEM;
139dd7e5540SHector Martin 		return -ENOMEM;
140fdd0bd88SChung-Hsien Hsu 	}
141fdd0bd88SChung-Hsien Hsu 
142dd7e5540SHector Martin 	datalen = size;
143fdd0bd88SChung-Hsien Hsu 	cumulative_len = 0;
144fdd0bd88SChung-Hsien Hsu 	do {
145fdd0bd88SChung-Hsien Hsu 		if (datalen > MAX_CHUNK_LEN) {
146fdd0bd88SChung-Hsien Hsu 			chunk_len = MAX_CHUNK_LEN;
147fdd0bd88SChung-Hsien Hsu 		} else {
148fdd0bd88SChung-Hsien Hsu 			chunk_len = datalen;
149fdd0bd88SChung-Hsien Hsu 			dl_flag |= DL_END;
150fdd0bd88SChung-Hsien Hsu 		}
151dd7e5540SHector Martin 		memcpy(chunk_buf->data, data + cumulative_len, chunk_len);
152fdd0bd88SChung-Hsien Hsu 
153dd7e5540SHector Martin 		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len,
154dd7e5540SHector Martin 				       loadvar);
155fdd0bd88SChung-Hsien Hsu 
156fdd0bd88SChung-Hsien Hsu 		dl_flag &= ~DL_BEGIN;
157fdd0bd88SChung-Hsien Hsu 
158fdd0bd88SChung-Hsien Hsu 		cumulative_len += chunk_len;
159fdd0bd88SChung-Hsien Hsu 		datalen -= chunk_len;
160fdd0bd88SChung-Hsien Hsu 	} while ((datalen > 0) && (err == 0));
161fdd0bd88SChung-Hsien Hsu 
162fdd0bd88SChung-Hsien Hsu 	if (err) {
163dd7e5540SHector Martin 		bphy_err(drvr, "%s (%zu byte file) failed (%d)\n",
164dd7e5540SHector Martin 			 loadvar, size, err);
165dd7e5540SHector Martin 		/* Retrieve status and print */
166dd7e5540SHector Martin 		err = brcmf_fil_iovar_int_get(ifp, statvar, &status);
167fdd0bd88SChung-Hsien Hsu 		if (err)
168dd7e5540SHector Martin 			bphy_err(drvr, "get %s failed (%d)\n", statvar, err);
169fdd0bd88SChung-Hsien Hsu 		else
170dd7e5540SHector Martin 			brcmf_dbg(INFO, "%s=%d\n", statvar, status);
171fdd0bd88SChung-Hsien Hsu 		err = -EIO;
172fdd0bd88SChung-Hsien Hsu 	}
173fdd0bd88SChung-Hsien Hsu 
174fdd0bd88SChung-Hsien Hsu 	kfree(chunk_buf);
175dd7e5540SHector Martin 	return err;
176dd7e5540SHector Martin }
177dd7e5540SHector Martin 
brcmf_c_process_clm_blob(struct brcmf_if * ifp)178dd7e5540SHector Martin static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
179dd7e5540SHector Martin {
180dd7e5540SHector Martin 	struct brcmf_pub *drvr = ifp->drvr;
181dd7e5540SHector Martin 	struct brcmf_bus *bus = drvr->bus_if;
182dd7e5540SHector Martin 	const struct firmware *fw = NULL;
183dd7e5540SHector Martin 	s32 err;
184dd7e5540SHector Martin 
185dd7e5540SHector Martin 	brcmf_dbg(TRACE, "Enter\n");
186dd7e5540SHector Martin 
187dd7e5540SHector Martin 	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM);
188dd7e5540SHector Martin 	if (err || !fw) {
189dd7e5540SHector Martin 		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
190dd7e5540SHector Martin 			   err);
191dd7e5540SHector Martin 		return 0;
192dd7e5540SHector Martin 	}
193dd7e5540SHector Martin 
194dd7e5540SHector Martin 	err = brcmf_c_download_blob(ifp, fw->data, fw->size,
195dd7e5540SHector Martin 				    "clmload", "clmload_status");
196dd7e5540SHector Martin 
197dd7e5540SHector Martin 	release_firmware(fw);
198dd7e5540SHector Martin 	return err;
199dd7e5540SHector Martin }
200dd7e5540SHector Martin 
brcmf_c_process_txcap_blob(struct brcmf_if * ifp)201dd7e5540SHector Martin static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp)
202dd7e5540SHector Martin {
203dd7e5540SHector Martin 	struct brcmf_pub *drvr = ifp->drvr;
204dd7e5540SHector Martin 	struct brcmf_bus *bus = drvr->bus_if;
205dd7e5540SHector Martin 	const struct firmware *fw = NULL;
206dd7e5540SHector Martin 	s32 err;
207dd7e5540SHector Martin 
208dd7e5540SHector Martin 	brcmf_dbg(TRACE, "Enter\n");
209dd7e5540SHector Martin 
210dd7e5540SHector Martin 	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP);
211dd7e5540SHector Martin 	if (err || !fw) {
212dd7e5540SHector Martin 		brcmf_info("no txcap_blob available (err=%d)\n", err);
213dd7e5540SHector Martin 		return 0;
214dd7e5540SHector Martin 	}
215dd7e5540SHector Martin 
216dd7e5540SHector Martin 	brcmf_info("TxCap blob found, loading\n");
217dd7e5540SHector Martin 	err = brcmf_c_download_blob(ifp, fw->data, fw->size,
218dd7e5540SHector Martin 				    "txcapload", "txcapload_status");
219dd7e5540SHector Martin 
220dd7e5540SHector Martin 	release_firmware(fw);
221fdd0bd88SChung-Hsien Hsu 	return err;
222fdd0bd88SChung-Hsien Hsu }
223fdd0bd88SChung-Hsien Hsu 
brcmf_c_set_cur_etheraddr(struct brcmf_if * ifp,const u8 * addr)224cf1239e5SHans de Goede int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr)
225cf1239e5SHans de Goede {
226cf1239e5SHans de Goede 	s32 err;
227cf1239e5SHans de Goede 
228cf1239e5SHans de Goede 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", addr, ETH_ALEN);
229cf1239e5SHans de Goede 	if (err < 0)
230cf1239e5SHans de Goede 		bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err);
231cf1239e5SHans de Goede 
232cf1239e5SHans de Goede 	return err;
233cf1239e5SHans de Goede }
234cf1239e5SHans de Goede 
2354af4c0b9SHans de Goede /* On some boards there is no eeprom to hold the nvram, in this case instead
2364af4c0b9SHans de Goede  * a board specific nvram is loaded from /lib/firmware. On most boards the
2374af4c0b9SHans de Goede  * macaddr setting in the /lib/firmware nvram file is ignored because the
2384af4c0b9SHans de Goede  * wifibt chip has a unique MAC programmed into the chip itself.
2394af4c0b9SHans de Goede  * But in some cases the actual MAC from the /lib/firmware nvram file gets
2404af4c0b9SHans de Goede  * used, leading to MAC conflicts.
2414af4c0b9SHans de Goede  * The MAC addresses in the troublesome nvram files seem to all come from
2424af4c0b9SHans de Goede  * the same nvram file template, so we only need to check for 1 known
2434af4c0b9SHans de Goede  * address to detect this.
2444af4c0b9SHans de Goede  */
2454af4c0b9SHans de Goede static const u8 brcmf_default_mac_address[ETH_ALEN] = {
2464af4c0b9SHans de Goede 	0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38
2474af4c0b9SHans de Goede };
2484af4c0b9SHans de Goede 
brcmf_c_process_cal_blob(struct brcmf_if * ifp)249*5b3ee998SHector Martin static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)
250*5b3ee998SHector Martin {
251*5b3ee998SHector Martin 	struct brcmf_pub *drvr = ifp->drvr;
252*5b3ee998SHector Martin 	struct brcmf_mp_device *settings = drvr->settings;
253*5b3ee998SHector Martin 	s32 err;
254*5b3ee998SHector Martin 
255*5b3ee998SHector Martin 	brcmf_dbg(TRACE, "Enter\n");
256*5b3ee998SHector Martin 
257*5b3ee998SHector Martin 	if (!settings->cal_blob || !settings->cal_size)
258*5b3ee998SHector Martin 		return 0;
259*5b3ee998SHector Martin 
260*5b3ee998SHector Martin 	brcmf_info("Calibration blob provided by platform, loading\n");
261*5b3ee998SHector Martin 	err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size,
262*5b3ee998SHector Martin 				    "calload", "calload_status");
263*5b3ee998SHector Martin 	return err;
264*5b3ee998SHector Martin }
265*5b3ee998SHector Martin 
brcmf_c_preinit_dcmds(struct brcmf_if * ifp)26605491d2cSKalle Valo int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
26705491d2cSKalle Valo {
268dcb1471bSRafał Miłecki 	struct brcmf_pub *drvr = ifp->drvr;
26905491d2cSKalle Valo 	s8 eventmask[BRCMF_EVENTING_MASK_LEN];
27005491d2cSKalle Valo 	u8 buf[BRCMF_DCMD_SMLEN];
271756a2b39SArend Van Spriel 	struct brcmf_bus *bus;
27205491d2cSKalle Valo 	struct brcmf_rev_info_le revinfo;
27305491d2cSKalle Valo 	struct brcmf_rev_info *ri;
274fdd0bd88SChung-Hsien Hsu 	char *clmver;
27505491d2cSKalle Valo 	char *ptr;
27605491d2cSKalle Valo 	s32 err;
27705491d2cSKalle Valo 
278716c220bSPavel Löbl 	if (is_valid_ether_addr(ifp->mac_addr)) {
279716c220bSPavel Löbl 		/* set mac address */
280cf1239e5SHans de Goede 		err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
281cf1239e5SHans de Goede 		if (err < 0)
282716c220bSPavel Löbl 			goto done;
283716c220bSPavel Löbl 	} else {
284716c220bSPavel Löbl 		/* retrieve mac address */
28505491d2cSKalle Valo 		err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
28605491d2cSKalle Valo 					       sizeof(ifp->mac_addr));
28705491d2cSKalle Valo 		if (err < 0) {
288dcb1471bSRafał Miłecki 			bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
28905491d2cSKalle Valo 			goto done;
29005491d2cSKalle Valo 		}
2914af4c0b9SHans de Goede 
2924af4c0b9SHans de Goede 		if (ether_addr_equal_unaligned(ifp->mac_addr, brcmf_default_mac_address)) {
2934af4c0b9SHans de Goede 			bphy_err(drvr, "Default MAC is used, replacing with random MAC to avoid conflicts\n");
2944af4c0b9SHans de Goede 			eth_random_addr(ifp->mac_addr);
2954af4c0b9SHans de Goede 			ifp->ndev->addr_assign_type = NET_ADDR_RANDOM;
2964af4c0b9SHans de Goede 			err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
2974af4c0b9SHans de Goede 			if (err < 0)
2984af4c0b9SHans de Goede 				goto done;
2994af4c0b9SHans de Goede 		}
300716c220bSPavel Löbl 	}
301716c220bSPavel Löbl 
30205491d2cSKalle Valo 	memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
3031eb4e9f6SWright Feng 	memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
30405491d2cSKalle Valo 
305756a2b39SArend Van Spriel 	bus = ifp->drvr->bus_if;
306756a2b39SArend Van Spriel 	ri = &ifp->drvr->revinfo;
307756a2b39SArend Van Spriel 
30805491d2cSKalle Valo 	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
30905491d2cSKalle Valo 				     &revinfo, sizeof(revinfo));
31005491d2cSKalle Valo 	if (err < 0) {
311dcb1471bSRafał Miłecki 		bphy_err(drvr, "retrieving revision info failed, %d\n", err);
312bf99f11dSWolfram Sang 		strscpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
31305491d2cSKalle Valo 	} else {
31405491d2cSKalle Valo 		ri->vendorid = le32_to_cpu(revinfo.vendorid);
31505491d2cSKalle Valo 		ri->deviceid = le32_to_cpu(revinfo.deviceid);
31605491d2cSKalle Valo 		ri->radiorev = le32_to_cpu(revinfo.radiorev);
31705491d2cSKalle Valo 		ri->corerev = le32_to_cpu(revinfo.corerev);
31805491d2cSKalle Valo 		ri->boardid = le32_to_cpu(revinfo.boardid);
31905491d2cSKalle Valo 		ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
32005491d2cSKalle Valo 		ri->boardrev = le32_to_cpu(revinfo.boardrev);
32105491d2cSKalle Valo 		ri->driverrev = le32_to_cpu(revinfo.driverrev);
32205491d2cSKalle Valo 		ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
32305491d2cSKalle Valo 		ri->bus = le32_to_cpu(revinfo.bus);
32405491d2cSKalle Valo 		ri->phytype = le32_to_cpu(revinfo.phytype);
32505491d2cSKalle Valo 		ri->phyrev = le32_to_cpu(revinfo.phyrev);
32605491d2cSKalle Valo 		ri->anarev = le32_to_cpu(revinfo.anarev);
32705491d2cSKalle Valo 		ri->chippkg = le32_to_cpu(revinfo.chippkg);
32805491d2cSKalle Valo 		ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
329756a2b39SArend Van Spriel 
330856d5a01SArend Van Spriel 		/* use revinfo if not known yet */
331756a2b39SArend Van Spriel 		if (!bus->chip) {
332756a2b39SArend Van Spriel 			bus->chip = le32_to_cpu(revinfo.chipnum);
333756a2b39SArend Van Spriel 			bus->chiprev = le32_to_cpu(revinfo.chiprev);
334756a2b39SArend Van Spriel 		}
33505491d2cSKalle Valo 	}
33605491d2cSKalle Valo 	ri->result = err;
33705491d2cSKalle Valo 
338756a2b39SArend Van Spriel 	if (bus->chip)
339756a2b39SArend Van Spriel 		brcmf_chip_name(bus->chip, bus->chiprev,
340756a2b39SArend Van Spriel 				ri->chipname, sizeof(ri->chipname));
341756a2b39SArend Van Spriel 
342fdd0bd88SChung-Hsien Hsu 	/* Do any CLM downloading */
343fdd0bd88SChung-Hsien Hsu 	err = brcmf_c_process_clm_blob(ifp);
344fdd0bd88SChung-Hsien Hsu 	if (err < 0) {
345dcb1471bSRafał Miłecki 		bphy_err(drvr, "download CLM blob file failed, %d\n", err);
346fdd0bd88SChung-Hsien Hsu 		goto done;
347fdd0bd88SChung-Hsien Hsu 	}
348fdd0bd88SChung-Hsien Hsu 
349dd7e5540SHector Martin 	/* Do TxCap downloading, if needed */
350dd7e5540SHector Martin 	err = brcmf_c_process_txcap_blob(ifp);
351dd7e5540SHector Martin 	if (err < 0) {
352dd7e5540SHector Martin 		bphy_err(drvr, "download TxCap blob file failed, %d\n", err);
353dd7e5540SHector Martin 		goto done;
354dd7e5540SHector Martin 	}
355dd7e5540SHector Martin 
356*5b3ee998SHector Martin 	/* Download external calibration blob, if available */
357*5b3ee998SHector Martin 	err = brcmf_c_process_cal_blob(ifp);
358*5b3ee998SHector Martin 	if (err < 0) {
359*5b3ee998SHector Martin 		bphy_err(drvr, "download calibration blob file failed, %d\n", err);
360*5b3ee998SHector Martin 		goto done;
361*5b3ee998SHector Martin 	}
362*5b3ee998SHector Martin 
36305491d2cSKalle Valo 	/* query for 'ver' to get version info from firmware */
36405491d2cSKalle Valo 	memset(buf, 0, sizeof(buf));
36505491d2cSKalle Valo 	err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
36605491d2cSKalle Valo 	if (err < 0) {
367dcb1471bSRafał Miłecki 		bphy_err(drvr, "Retrieving version information failed, %d\n",
36805491d2cSKalle Valo 			 err);
36905491d2cSKalle Valo 		goto done;
37005491d2cSKalle Valo 	}
3710a06cadcSJisoo Jang 	buf[sizeof(buf) - 1] = '\0';
37205491d2cSKalle Valo 	ptr = (char *)buf;
37305491d2cSKalle Valo 	strsep(&ptr, "\n");
37405491d2cSKalle Valo 
37505491d2cSKalle Valo 	/* Print fw version info */
376756a2b39SArend Van Spriel 	brcmf_info("Firmware: %s %s\n", ri->chipname, buf);
37705491d2cSKalle Valo 
37805491d2cSKalle Valo 	/* locate firmware version number for ethtool */
379683b9728SJisoo Jang 	ptr = strrchr(buf, ' ');
380683b9728SJisoo Jang 	if (!ptr) {
381683b9728SJisoo Jang 		bphy_err(drvr, "Retrieving version number failed");
382683b9728SJisoo Jang 		goto done;
383683b9728SJisoo Jang 	}
384683b9728SJisoo Jang 	strscpy(ifp->drvr->fwver, ptr + 1, sizeof(ifp->drvr->fwver));
38505491d2cSKalle Valo 
386fdd0bd88SChung-Hsien Hsu 	/* Query for 'clmver' to get CLM version info from firmware */
387fdd0bd88SChung-Hsien Hsu 	memset(buf, 0, sizeof(buf));
388fdd0bd88SChung-Hsien Hsu 	err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
389fdd0bd88SChung-Hsien Hsu 	if (err) {
390fdd0bd88SChung-Hsien Hsu 		brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
391fdd0bd88SChung-Hsien Hsu 	} else {
392660145d7SJisoo Jang 		buf[sizeof(buf) - 1] = '\0';
393fdd0bd88SChung-Hsien Hsu 		clmver = (char *)buf;
394fdd0bd88SChung-Hsien Hsu 
395fdd0bd88SChung-Hsien Hsu 		/* Replace all newline/linefeed characters with space
396fdd0bd88SChung-Hsien Hsu 		 * character
397fdd0bd88SChung-Hsien Hsu 		 */
398cb18e2e9SRasmus Villemoes 		strreplace(clmver, '\n', ' ');
399fdd0bd88SChung-Hsien Hsu 
400660145d7SJisoo Jang 		/* store CLM version for adding it to revinfo debugfs file */
401660145d7SJisoo Jang 		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
402660145d7SJisoo Jang 
403fdd0bd88SChung-Hsien Hsu 		brcmf_dbg(INFO, "CLM version = %s\n", clmver);
404fdd0bd88SChung-Hsien Hsu 	}
405fdd0bd88SChung-Hsien Hsu 
40605491d2cSKalle Valo 	/* set mpc */
40705491d2cSKalle Valo 	err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
40805491d2cSKalle Valo 	if (err) {
409dcb1471bSRafał Miłecki 		bphy_err(drvr, "failed setting mpc\n");
41005491d2cSKalle Valo 		goto done;
41105491d2cSKalle Valo 	}
41205491d2cSKalle Valo 
4137705ba6fSArend van Spriel 	brcmf_c_set_joinpref_default(ifp);
41405491d2cSKalle Valo 
41505491d2cSKalle Valo 	/* Setup event_msgs, enable E_IF */
41605491d2cSKalle Valo 	err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
41705491d2cSKalle Valo 				       BRCMF_EVENTING_MASK_LEN);
41805491d2cSKalle Valo 	if (err) {
419dcb1471bSRafał Miłecki 		bphy_err(drvr, "Get event_msgs error (%d)\n", err);
42005491d2cSKalle Valo 		goto done;
42105491d2cSKalle Valo 	}
42205491d2cSKalle Valo 	setbit(eventmask, BRCMF_E_IF);
42305491d2cSKalle Valo 	err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
42405491d2cSKalle Valo 				       BRCMF_EVENTING_MASK_LEN);
42505491d2cSKalle Valo 	if (err) {
426dcb1471bSRafał Miłecki 		bphy_err(drvr, "Set event_msgs error (%d)\n", err);
42705491d2cSKalle Valo 		goto done;
42805491d2cSKalle Valo 	}
42905491d2cSKalle Valo 
43005491d2cSKalle Valo 	/* Setup default scan channel time */
43105491d2cSKalle Valo 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
43205491d2cSKalle Valo 				    BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
43305491d2cSKalle Valo 	if (err) {
434dcb1471bSRafał Miłecki 		bphy_err(drvr, "BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
43505491d2cSKalle Valo 			 err);
43605491d2cSKalle Valo 		goto done;
43705491d2cSKalle Valo 	}
43805491d2cSKalle Valo 
43905491d2cSKalle Valo 	/* Setup default scan unassoc time */
44005491d2cSKalle Valo 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
44105491d2cSKalle Valo 				    BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
44205491d2cSKalle Valo 	if (err) {
443dcb1471bSRafał Miłecki 		bphy_err(drvr, "BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
44405491d2cSKalle Valo 			 err);
44505491d2cSKalle Valo 		goto done;
44605491d2cSKalle Valo 	}
44705491d2cSKalle Valo 
4487bf65aa9SHante Meuleman 	/* Enable tx beamforming, errors can be ignored (not supported) */
4497bf65aa9SHante Meuleman 	(void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
45005491d2cSKalle Valo done:
45105491d2cSKalle Valo 	return err;
45205491d2cSKalle Valo }
45305491d2cSKalle Valo 
454087fa712SRafał Miłecki #ifndef CONFIG_BRCM_TRACING
__brcmf_err(struct brcmf_bus * bus,const char * func,const char * fmt,...)4555cc898fbSRafał Miłecki void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...)
456087fa712SRafał Miłecki {
457087fa712SRafał Miłecki 	struct va_format vaf;
458087fa712SRafał Miłecki 	va_list args;
459087fa712SRafał Miłecki 
460087fa712SRafał Miłecki 	va_start(args, fmt);
461087fa712SRafał Miłecki 
462087fa712SRafał Miłecki 	vaf.fmt = fmt;
463087fa712SRafał Miłecki 	vaf.va = &args;
4645cc898fbSRafał Miłecki 	if (bus)
4655cc898fbSRafał Miłecki 		dev_err(bus->dev, "%s: %pV", func, &vaf);
4665cc898fbSRafał Miłecki 	else
467087fa712SRafał Miłecki 		pr_err("%s: %pV", func, &vaf);
468087fa712SRafał Miłecki 
469087fa712SRafał Miłecki 	va_end(args);
470087fa712SRafał Miłecki }
471087fa712SRafał Miłecki #endif
472087fa712SRafał Miłecki 
47305491d2cSKalle Valo #if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
__brcmf_dbg(u32 level,const char * func,const char * fmt,...)47405491d2cSKalle Valo void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
47505491d2cSKalle Valo {
47605491d2cSKalle Valo 	struct va_format vaf = {
47705491d2cSKalle Valo 		.fmt = fmt,
47805491d2cSKalle Valo 	};
47905491d2cSKalle Valo 	va_list args;
48005491d2cSKalle Valo 
48105491d2cSKalle Valo 	va_start(args, fmt);
48205491d2cSKalle Valo 	vaf.va = &args;
48305491d2cSKalle Valo 	if (brcmf_msg_level & level)
48405491d2cSKalle Valo 		pr_debug("%s %pV", func, &vaf);
48505491d2cSKalle Valo 	trace_brcmf_dbg(level, func, &vaf);
48605491d2cSKalle Valo 	va_end(args);
48705491d2cSKalle Valo }
48805491d2cSKalle Valo #endif
4897d34b056SHante Meuleman 
brcmf_mp_attach(void)490d84d99e0SHante Meuleman static void brcmf_mp_attach(void)
4917d34b056SHante Meuleman {
4924d792895SHante Meuleman 	/* If module param firmware path is set then this will always be used,
4934d792895SHante Meuleman 	 * if not set then if available use the platform data version. To make
4944d792895SHante Meuleman 	 * sure it gets initialized at all, always copy the module param version
4954d792895SHante Meuleman 	 */
496bf99f11dSWolfram Sang 	strscpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
4977d34b056SHante Meuleman 		BRCMF_FW_ALTPATH_LEN);
4984d792895SHante Meuleman 	if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
4994d792895SHante Meuleman 	    (brcmf_mp_global.firmware_path[0] == '\0')) {
500bf99f11dSWolfram Sang 		strscpy(brcmf_mp_global.firmware_path,
5014d792895SHante Meuleman 			brcmfmac_pdata->fw_alternative_path,
5024d792895SHante Meuleman 			BRCMF_FW_ALTPATH_LEN);
5034d792895SHante Meuleman 	}
5047d34b056SHante Meuleman }
5057d34b056SHante Meuleman 
brcmf_get_module_param(struct device * dev,enum brcmf_bus_type bus_type,u32 chip,u32 chiprev)506af5b5e62SHante Meuleman struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
5074d792895SHante Meuleman 					       enum brcmf_bus_type bus_type,
5084d792895SHante Meuleman 					       u32 chip, u32 chiprev)
5098ea56be0SHante Meuleman {
510af5b5e62SHante Meuleman 	struct brcmf_mp_device *settings;
5114d792895SHante Meuleman 	struct brcmfmac_pd_device *device_pd;
512af5b5e62SHante Meuleman 	bool found;
5134d792895SHante Meuleman 	int i;
5144d792895SHante Meuleman 
515af5b5e62SHante Meuleman 	brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
516af5b5e62SHante Meuleman 		  chiprev);
517af5b5e62SHante Meuleman 	settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
518af5b5e62SHante Meuleman 	if (!settings)
519af5b5e62SHante Meuleman 		return NULL;
520af5b5e62SHante Meuleman 
521af5b5e62SHante Meuleman 	/* start by using the module paramaters */
522af5b5e62SHante Meuleman 	settings->p2p_enable = !!brcmf_p2p_enable;
523af5b5e62SHante Meuleman 	settings->feature_disable = brcmf_feature_disable;
524af5b5e62SHante Meuleman 	settings->fcmode = brcmf_fcmode;
525af5b5e62SHante Meuleman 	settings->roamoff = !!brcmf_roamoff;
52612590551SRafał Miłecki 	settings->iapp = !!brcmf_iapp_enable;
527af5b5e62SHante Meuleman #ifdef DEBUG
528af5b5e62SHante Meuleman 	settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
529af5b5e62SHante Meuleman #endif
530af5b5e62SHante Meuleman 
531af5b5e62SHante Meuleman 	if (bus_type == BRCMF_BUSTYPE_SDIO)
532af5b5e62SHante Meuleman 		settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
533af5b5e62SHante Meuleman 
534af5b5e62SHante Meuleman 	/* See if there is any device specific platform data configured */
535af5b5e62SHante Meuleman 	found = false;
5364d792895SHante Meuleman 	if (brcmfmac_pdata) {
5374d792895SHante Meuleman 		for (i = 0; i < brcmfmac_pdata->device_count; i++) {
5384d792895SHante Meuleman 			device_pd = &brcmfmac_pdata->devices[i];
5394d792895SHante Meuleman 			if ((device_pd->bus_type == bus_type) &&
5404d792895SHante Meuleman 			    (device_pd->id == chip) &&
5414d792895SHante Meuleman 			    ((device_pd->rev == chiprev) ||
5424d792895SHante Meuleman 			     (device_pd->rev == -1))) {
5434d792895SHante Meuleman 				brcmf_dbg(INFO, "Platform data for device found\n");
544af5b5e62SHante Meuleman 				settings->country_codes =
545af5b5e62SHante Meuleman 						device_pd->country_codes;
5464d792895SHante Meuleman 				if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
547af5b5e62SHante Meuleman 					memcpy(&settings->bus.sdio,
548af5b5e62SHante Meuleman 					       &device_pd->bus.sdio,
549af5b5e62SHante Meuleman 					       sizeof(settings->bus.sdio));
550af5b5e62SHante Meuleman 				found = true;
5514d792895SHante Meuleman 				break;
5524d792895SHante Meuleman 			}
5534d792895SHante Meuleman 		}
5544d792895SHante Meuleman 	}
555e457a8a0SRafał Miłecki 	if (!found) {
556bd1e82bbSHans de Goede 		/* No platform data for this device, try OF and DMI data */
557bd1e82bbSHans de Goede 		brcmf_dmi_probe(settings, chip, chiprev);
558554da386SHans de Goede 		brcmf_of_probe(dev, bus_type, settings);
5590f485805SHector Martin 		brcmf_acpi_probe(dev, bus_type, settings);
560af5b5e62SHante Meuleman 	}
561af5b5e62SHante Meuleman 	return settings;
5628ea56be0SHante Meuleman }
5638ea56be0SHante Meuleman 
brcmf_release_module_param(struct brcmf_mp_device * module_param)564af5b5e62SHante Meuleman void brcmf_release_module_param(struct brcmf_mp_device *module_param)
5657d34b056SHante Meuleman {
566af5b5e62SHante Meuleman 	kfree(module_param);
5677d34b056SHante Meuleman }
5687d34b056SHante Meuleman 
brcmf_common_pd_probe(struct platform_device * pdev)5698ea56be0SHante Meuleman static int __init brcmf_common_pd_probe(struct platform_device *pdev)
5708ea56be0SHante Meuleman {
5718ea56be0SHante Meuleman 	brcmf_dbg(INFO, "Enter\n");
5728ea56be0SHante Meuleman 
5738ea56be0SHante Meuleman 	brcmfmac_pdata = dev_get_platdata(&pdev->dev);
5748ea56be0SHante Meuleman 
5758ea56be0SHante Meuleman 	if (brcmfmac_pdata->power_on)
5768ea56be0SHante Meuleman 		brcmfmac_pdata->power_on();
5778ea56be0SHante Meuleman 
5788ea56be0SHante Meuleman 	return 0;
5798ea56be0SHante Meuleman }
5808ea56be0SHante Meuleman 
brcmf_common_pd_remove(struct platform_device * pdev)5818ea56be0SHante Meuleman static int brcmf_common_pd_remove(struct platform_device *pdev)
5828ea56be0SHante Meuleman {
5838ea56be0SHante Meuleman 	brcmf_dbg(INFO, "Enter\n");
5848ea56be0SHante Meuleman 
5858ea56be0SHante Meuleman 	if (brcmfmac_pdata->power_off)
5868ea56be0SHante Meuleman 		brcmfmac_pdata->power_off();
5878ea56be0SHante Meuleman 
5888ea56be0SHante Meuleman 	return 0;
5898ea56be0SHante Meuleman }
5908ea56be0SHante Meuleman 
5918ea56be0SHante Meuleman static struct platform_driver brcmf_pd = {
5928ea56be0SHante Meuleman 	.remove		= brcmf_common_pd_remove,
5938ea56be0SHante Meuleman 	.driver		= {
5944d792895SHante Meuleman 		.name	= BRCMFMAC_PDATA_NAME,
5958ea56be0SHante Meuleman 	}
5968ea56be0SHante Meuleman };
5978ea56be0SHante Meuleman 
brcmfmac_module_init(void)598d84d99e0SHante Meuleman static int __init brcmfmac_module_init(void)
599d84d99e0SHante Meuleman {
600d84d99e0SHante Meuleman 	int err;
601d84d99e0SHante Meuleman 
6028ea56be0SHante Meuleman 	/* Get the platform data (if available) for our devices */
6038ea56be0SHante Meuleman 	err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
6048ea56be0SHante Meuleman 	if (err == -ENODEV)
6058ea56be0SHante Meuleman 		brcmf_dbg(INFO, "No platform data available.\n");
6068ea56be0SHante Meuleman 
607d84d99e0SHante Meuleman 	/* Initialize global module paramaters */
608d84d99e0SHante Meuleman 	brcmf_mp_attach();
609d84d99e0SHante Meuleman 
610d84d99e0SHante Meuleman 	/* Continue the initialization by registering the different busses */
611d84d99e0SHante Meuleman 	err = brcmf_core_init();
6128ea56be0SHante Meuleman 	if (err) {
6138ea56be0SHante Meuleman 		if (brcmfmac_pdata)
6148ea56be0SHante Meuleman 			platform_driver_unregister(&brcmf_pd);
6158ea56be0SHante Meuleman 	}
616d84d99e0SHante Meuleman 
617d84d99e0SHante Meuleman 	return err;
618d84d99e0SHante Meuleman }
619d84d99e0SHante Meuleman 
brcmfmac_module_exit(void)620d84d99e0SHante Meuleman static void __exit brcmfmac_module_exit(void)
621d84d99e0SHante Meuleman {
622d84d99e0SHante Meuleman 	brcmf_core_exit();
6238ea56be0SHante Meuleman 	if (brcmfmac_pdata)
6248ea56be0SHante Meuleman 		platform_driver_unregister(&brcmf_pd);
625d84d99e0SHante Meuleman }
626d84d99e0SHante Meuleman 
627d84d99e0SHante Meuleman module_init(brcmfmac_module_init);
628d84d99e0SHante Meuleman module_exit(brcmfmac_module_exit);
629d84d99e0SHante Meuleman 
630