xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmfmac/common.c (revision 902136e0fe112383ec64d2ef43a446063b5e6417)
1b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2b4c3e9b5SBjoern A. Zeeb /*
3b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2010 Broadcom Corporation
4b4c3e9b5SBjoern A. Zeeb  */
5b4c3e9b5SBjoern A. Zeeb 
6*902136e0SBjoern A. Zeeb #if defined(__FreeBSD__)
7*902136e0SBjoern A. Zeeb #define	LINUXKPI_PARAM_PREFIX	brcmfmac_
8*902136e0SBjoern A. Zeeb #endif
9*902136e0SBjoern A. Zeeb 
10b4c3e9b5SBjoern A. Zeeb #include <linux/kernel.h>
11b4c3e9b5SBjoern A. Zeeb #include <linux/string.h>
12b4c3e9b5SBjoern A. Zeeb #include <linux/netdevice.h>
13b4c3e9b5SBjoern A. Zeeb #include <linux/module.h>
14b4c3e9b5SBjoern A. Zeeb #include <linux/firmware.h>
15b4c3e9b5SBjoern A. Zeeb #include <brcmu_wifi.h>
16b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
17b4c3e9b5SBjoern A. Zeeb #include "core.h"
18b4c3e9b5SBjoern A. Zeeb #include "bus.h"
19b4c3e9b5SBjoern A. Zeeb #include "debug.h"
20b4c3e9b5SBjoern A. Zeeb #include "fwil.h"
21b4c3e9b5SBjoern A. Zeeb #include "fwil_types.h"
22b4c3e9b5SBjoern A. Zeeb #include "tracepoint.h"
23b4c3e9b5SBjoern A. Zeeb #include "common.h"
24b4c3e9b5SBjoern A. Zeeb #include "of.h"
25b4c3e9b5SBjoern A. Zeeb #include "firmware.h"
26b4c3e9b5SBjoern A. Zeeb #include "chip.h"
27b4c3e9b5SBjoern A. Zeeb 
28b4c3e9b5SBjoern A. Zeeb MODULE_AUTHOR("Broadcom Corporation");
29b4c3e9b5SBjoern A. Zeeb MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
30b4c3e9b5SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
31*902136e0SBjoern A. Zeeb #if defined(__FreeBSD__)
32*902136e0SBjoern A. Zeeb MODULE_DEPEND(brcmfmac, brcmutil, 1, 1, 1);
33*902136e0SBjoern A. Zeeb MODULE_DEPEND(brcmfmac, linuxkpi, 1, 1, 1);
34*902136e0SBjoern A. Zeeb MODULE_DEPEND(brcmfmac, linuxkpi_wlan, 1, 1, 1);
35*902136e0SBjoern A. Zeeb MODULE_DEPEND(brcmfmac, lindebugfs, 1, 1, 1);   /* XXX-BZ someone should fix this */
36*902136e0SBjoern A. Zeeb #endif
37b4c3e9b5SBjoern A. Zeeb 
38b4c3e9b5SBjoern A. Zeeb #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40
39b4c3e9b5SBjoern A. Zeeb #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40
40b4c3e9b5SBjoern A. Zeeb 
41b4c3e9b5SBjoern A. Zeeb /* default boost value for RSSI_DELTA in preferred join selection */
42b4c3e9b5SBjoern A. Zeeb #define BRCMF_JOIN_PREF_RSSI_BOOST	8
43b4c3e9b5SBjoern A. Zeeb 
44b4c3e9b5SBjoern A. Zeeb #define BRCMF_DEFAULT_TXGLOM_SIZE	32  /* max tx frames in glom chain */
45b4c3e9b5SBjoern A. Zeeb 
46b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
47b4c3e9b5SBjoern A. Zeeb module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
48b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
49b4c3e9b5SBjoern A. Zeeb 
50b4c3e9b5SBjoern A. Zeeb /* Debug level configuration. See debug.h for bits, sysfs modifiable */
51b4c3e9b5SBjoern A. Zeeb int brcmf_msg_level;
52b4c3e9b5SBjoern A. Zeeb module_param_named(debug, brcmf_msg_level, int, 0600);
53b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(debug, "Level of debug output");
54b4c3e9b5SBjoern A. Zeeb 
55b4c3e9b5SBjoern A. Zeeb static int brcmf_p2p_enable;
56b4c3e9b5SBjoern A. Zeeb module_param_named(p2pon, brcmf_p2p_enable, int, 0);
57b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(p2pon, "Enable legacy p2p management functionality");
58b4c3e9b5SBjoern A. Zeeb 
59b4c3e9b5SBjoern A. Zeeb static int brcmf_feature_disable;
60b4c3e9b5SBjoern A. Zeeb module_param_named(feature_disable, brcmf_feature_disable, int, 0);
61b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(feature_disable, "Disable features");
62b4c3e9b5SBjoern A. Zeeb 
63b4c3e9b5SBjoern A. Zeeb static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
64b4c3e9b5SBjoern A. Zeeb module_param_string(alternative_fw_path, brcmf_firmware_path,
65b4c3e9b5SBjoern A. Zeeb 		    BRCMF_FW_ALTPATH_LEN, 0400);
66b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
67b4c3e9b5SBjoern A. Zeeb 
68b4c3e9b5SBjoern A. Zeeb static int brcmf_fcmode;
69b4c3e9b5SBjoern A. Zeeb module_param_named(fcmode, brcmf_fcmode, int, 0);
70b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
71b4c3e9b5SBjoern A. Zeeb 
72b4c3e9b5SBjoern A. Zeeb static int brcmf_roamoff;
73b4c3e9b5SBjoern A. Zeeb module_param_named(roamoff, brcmf_roamoff, int, 0400);
74b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
75b4c3e9b5SBjoern A. Zeeb 
76b4c3e9b5SBjoern A. Zeeb static int brcmf_iapp_enable;
77b4c3e9b5SBjoern A. Zeeb module_param_named(iapp, brcmf_iapp_enable, int, 0);
78b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
79b4c3e9b5SBjoern A. Zeeb 
80b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
81b4c3e9b5SBjoern A. Zeeb /* always succeed brcmf_bus_started() */
82b4c3e9b5SBjoern A. Zeeb static int brcmf_ignore_probe_fail;
83b4c3e9b5SBjoern A. Zeeb module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
84b4c3e9b5SBjoern A. Zeeb MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
85b4c3e9b5SBjoern A. Zeeb #endif
86b4c3e9b5SBjoern A. Zeeb 
87b4c3e9b5SBjoern A. Zeeb static struct brcmfmac_platform_data *brcmfmac_pdata;
88b4c3e9b5SBjoern A. Zeeb struct brcmf_mp_global_t brcmf_mp_global;
89b4c3e9b5SBjoern A. Zeeb 
brcmf_c_set_joinpref_default(struct brcmf_if * ifp)90b4c3e9b5SBjoern A. Zeeb void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
91b4c3e9b5SBjoern A. Zeeb {
92b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
93b4c3e9b5SBjoern A. Zeeb 	struct brcmf_join_pref_params join_pref_params[2];
94b4c3e9b5SBjoern A. Zeeb 	int err;
95b4c3e9b5SBjoern A. Zeeb 
96b4c3e9b5SBjoern A. Zeeb 	/* Setup join_pref to select target by RSSI (boost on 5GHz) */
97b4c3e9b5SBjoern A. Zeeb 	join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
98b4c3e9b5SBjoern A. Zeeb 	join_pref_params[0].len = 2;
99b4c3e9b5SBjoern A. Zeeb 	join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
100b4c3e9b5SBjoern A. Zeeb 	join_pref_params[0].band = WLC_BAND_5G;
101b4c3e9b5SBjoern A. Zeeb 
102b4c3e9b5SBjoern A. Zeeb 	join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
103b4c3e9b5SBjoern A. Zeeb 	join_pref_params[1].len = 2;
104b4c3e9b5SBjoern A. Zeeb 	join_pref_params[1].rssi_gain = 0;
105b4c3e9b5SBjoern A. Zeeb 	join_pref_params[1].band = 0;
106b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
107b4c3e9b5SBjoern A. Zeeb 				       sizeof(join_pref_params));
108b4c3e9b5SBjoern A. Zeeb 	if (err)
109b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "Set join_pref error (%d)\n", err);
110b4c3e9b5SBjoern A. Zeeb }
111b4c3e9b5SBjoern A. Zeeb 
brcmf_c_download(struct brcmf_if * ifp,u16 flag,struct brcmf_dload_data_le * dload_buf,u32 len,const char * var)112b4c3e9b5SBjoern A. Zeeb static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
113b4c3e9b5SBjoern A. Zeeb 			    struct brcmf_dload_data_le *dload_buf,
114b4c3e9b5SBjoern A. Zeeb 			    u32 len, const char *var)
115b4c3e9b5SBjoern A. Zeeb {
116b4c3e9b5SBjoern A. Zeeb 	s32 err;
117b4c3e9b5SBjoern A. Zeeb 
118b4c3e9b5SBjoern A. Zeeb 	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
119b4c3e9b5SBjoern A. Zeeb 	dload_buf->flag = cpu_to_le16(flag);
120b4c3e9b5SBjoern A. Zeeb 	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
121b4c3e9b5SBjoern A. Zeeb 	dload_buf->len = cpu_to_le32(len);
122b4c3e9b5SBjoern A. Zeeb 	dload_buf->crc = cpu_to_le32(0);
123b4c3e9b5SBjoern A. Zeeb 
124b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_set(ifp, var, dload_buf,
125b4c3e9b5SBjoern A. Zeeb 				       struct_size(dload_buf, data, len));
126b4c3e9b5SBjoern A. Zeeb 
127b4c3e9b5SBjoern A. Zeeb 	return err;
128b4c3e9b5SBjoern A. Zeeb }
129b4c3e9b5SBjoern A. Zeeb 
brcmf_c_download_blob(struct brcmf_if * ifp,const void * data,size_t size,const char * loadvar,const char * statvar)130b4c3e9b5SBjoern A. Zeeb static int brcmf_c_download_blob(struct brcmf_if *ifp,
131*902136e0SBjoern A. Zeeb #if defined(__linux__)
132b4c3e9b5SBjoern A. Zeeb 				 const void *data, size_t size,
133*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
134*902136e0SBjoern A. Zeeb 				 const u8 *data, size_t size,
135*902136e0SBjoern A. Zeeb #endif
136b4c3e9b5SBjoern A. Zeeb 				 const char *loadvar, const char *statvar)
137b4c3e9b5SBjoern A. Zeeb {
138b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
139b4c3e9b5SBjoern A. Zeeb 	struct brcmf_dload_data_le *chunk_buf;
140b4c3e9b5SBjoern A. Zeeb 	u32 chunk_len;
141b4c3e9b5SBjoern A. Zeeb 	u32 datalen;
142b4c3e9b5SBjoern A. Zeeb 	u32 cumulative_len;
143b4c3e9b5SBjoern A. Zeeb 	u16 dl_flag = DL_BEGIN;
144b4c3e9b5SBjoern A. Zeeb 	u32 status;
145b4c3e9b5SBjoern A. Zeeb 	s32 err;
146b4c3e9b5SBjoern A. Zeeb 
147b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "Enter\n");
148b4c3e9b5SBjoern A. Zeeb 
149b4c3e9b5SBjoern A. Zeeb 	chunk_buf = kzalloc(struct_size(chunk_buf, data, MAX_CHUNK_LEN),
150b4c3e9b5SBjoern A. Zeeb 			    GFP_KERNEL);
151b4c3e9b5SBjoern A. Zeeb 	if (!chunk_buf) {
152b4c3e9b5SBjoern A. Zeeb 		err = -ENOMEM;
153b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
154b4c3e9b5SBjoern A. Zeeb 	}
155b4c3e9b5SBjoern A. Zeeb 
156b4c3e9b5SBjoern A. Zeeb 	datalen = size;
157b4c3e9b5SBjoern A. Zeeb 	cumulative_len = 0;
158b4c3e9b5SBjoern A. Zeeb 	do {
159b4c3e9b5SBjoern A. Zeeb 		if (datalen > MAX_CHUNK_LEN) {
160b4c3e9b5SBjoern A. Zeeb 			chunk_len = MAX_CHUNK_LEN;
161b4c3e9b5SBjoern A. Zeeb 		} else {
162b4c3e9b5SBjoern A. Zeeb 			chunk_len = datalen;
163b4c3e9b5SBjoern A. Zeeb 			dl_flag |= DL_END;
164b4c3e9b5SBjoern A. Zeeb 		}
165b4c3e9b5SBjoern A. Zeeb 		memcpy(chunk_buf->data, data + cumulative_len, chunk_len);
166b4c3e9b5SBjoern A. Zeeb 
167b4c3e9b5SBjoern A. Zeeb 		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len,
168b4c3e9b5SBjoern A. Zeeb 				       loadvar);
169b4c3e9b5SBjoern A. Zeeb 
170b4c3e9b5SBjoern A. Zeeb 		dl_flag &= ~DL_BEGIN;
171b4c3e9b5SBjoern A. Zeeb 
172b4c3e9b5SBjoern A. Zeeb 		cumulative_len += chunk_len;
173b4c3e9b5SBjoern A. Zeeb 		datalen -= chunk_len;
174b4c3e9b5SBjoern A. Zeeb 	} while ((datalen > 0) && (err == 0));
175b4c3e9b5SBjoern A. Zeeb 
176b4c3e9b5SBjoern A. Zeeb 	if (err) {
177b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "%s (%zu byte file) failed (%d)\n",
178b4c3e9b5SBjoern A. Zeeb 			 loadvar, size, err);
179b4c3e9b5SBjoern A. Zeeb 		/* Retrieve status and print */
180b4c3e9b5SBjoern A. Zeeb 		err = brcmf_fil_iovar_int_get(ifp, statvar, &status);
181b4c3e9b5SBjoern A. Zeeb 		if (err)
182b4c3e9b5SBjoern A. Zeeb 			bphy_err(drvr, "get %s failed (%d)\n", statvar, err);
183b4c3e9b5SBjoern A. Zeeb 		else
184b4c3e9b5SBjoern A. Zeeb 			brcmf_dbg(INFO, "%s=%d\n", statvar, status);
185b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
186b4c3e9b5SBjoern A. Zeeb 	}
187b4c3e9b5SBjoern A. Zeeb 
188b4c3e9b5SBjoern A. Zeeb 	kfree(chunk_buf);
189b4c3e9b5SBjoern A. Zeeb 	return err;
190b4c3e9b5SBjoern A. Zeeb }
191b4c3e9b5SBjoern A. Zeeb 
brcmf_c_process_clm_blob(struct brcmf_if * ifp)192b4c3e9b5SBjoern A. Zeeb static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
193b4c3e9b5SBjoern A. Zeeb {
194b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
195b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus = drvr->bus_if;
196b4c3e9b5SBjoern A. Zeeb 	const struct firmware *fw = NULL;
197b4c3e9b5SBjoern A. Zeeb 	s32 err;
198b4c3e9b5SBjoern A. Zeeb 
199b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "Enter\n");
200b4c3e9b5SBjoern A. Zeeb 
201b4c3e9b5SBjoern A. Zeeb 	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM);
202b4c3e9b5SBjoern A. Zeeb 	if (err || !fw) {
203b4c3e9b5SBjoern A. Zeeb 		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
204b4c3e9b5SBjoern A. Zeeb 			   err);
205b4c3e9b5SBjoern A. Zeeb 		return 0;
206b4c3e9b5SBjoern A. Zeeb 	}
207b4c3e9b5SBjoern A. Zeeb 
208b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_download_blob(ifp, fw->data, fw->size,
209b4c3e9b5SBjoern A. Zeeb 				    "clmload", "clmload_status");
210b4c3e9b5SBjoern A. Zeeb 
211b4c3e9b5SBjoern A. Zeeb 	release_firmware(fw);
212b4c3e9b5SBjoern A. Zeeb 	return err;
213b4c3e9b5SBjoern A. Zeeb }
214b4c3e9b5SBjoern A. Zeeb 
brcmf_c_process_txcap_blob(struct brcmf_if * ifp)215b4c3e9b5SBjoern A. Zeeb static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp)
216b4c3e9b5SBjoern A. Zeeb {
217b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
218b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus = drvr->bus_if;
219b4c3e9b5SBjoern A. Zeeb 	const struct firmware *fw = NULL;
220b4c3e9b5SBjoern A. Zeeb 	s32 err;
221b4c3e9b5SBjoern A. Zeeb 
222b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "Enter\n");
223b4c3e9b5SBjoern A. Zeeb 
224b4c3e9b5SBjoern A. Zeeb 	err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP);
225b4c3e9b5SBjoern A. Zeeb 	if (err || !fw) {
226b4c3e9b5SBjoern A. Zeeb 		brcmf_info("no txcap_blob available (err=%d)\n", err);
227b4c3e9b5SBjoern A. Zeeb 		return 0;
228b4c3e9b5SBjoern A. Zeeb 	}
229b4c3e9b5SBjoern A. Zeeb 
230b4c3e9b5SBjoern A. Zeeb 	brcmf_info("TxCap blob found, loading\n");
231b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_download_blob(ifp, fw->data, fw->size,
232b4c3e9b5SBjoern A. Zeeb 				    "txcapload", "txcapload_status");
233b4c3e9b5SBjoern A. Zeeb 
234b4c3e9b5SBjoern A. Zeeb 	release_firmware(fw);
235b4c3e9b5SBjoern A. Zeeb 	return err;
236b4c3e9b5SBjoern A. Zeeb }
237b4c3e9b5SBjoern A. Zeeb 
brcmf_c_set_cur_etheraddr(struct brcmf_if * ifp,const u8 * addr)238b4c3e9b5SBjoern A. Zeeb int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr)
239b4c3e9b5SBjoern A. Zeeb {
240b4c3e9b5SBjoern A. Zeeb 	s32 err;
241b4c3e9b5SBjoern A. Zeeb 
242b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", addr, ETH_ALEN);
243b4c3e9b5SBjoern A. Zeeb 	if (err < 0)
244b4c3e9b5SBjoern A. Zeeb 		bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err);
245b4c3e9b5SBjoern A. Zeeb 
246b4c3e9b5SBjoern A. Zeeb 	return err;
247b4c3e9b5SBjoern A. Zeeb }
248b4c3e9b5SBjoern A. Zeeb 
249b4c3e9b5SBjoern A. Zeeb /* On some boards there is no eeprom to hold the nvram, in this case instead
250b4c3e9b5SBjoern A. Zeeb  * a board specific nvram is loaded from /lib/firmware. On most boards the
251b4c3e9b5SBjoern A. Zeeb  * macaddr setting in the /lib/firmware nvram file is ignored because the
252b4c3e9b5SBjoern A. Zeeb  * wifibt chip has a unique MAC programmed into the chip itself.
253b4c3e9b5SBjoern A. Zeeb  * But in some cases the actual MAC from the /lib/firmware nvram file gets
254b4c3e9b5SBjoern A. Zeeb  * used, leading to MAC conflicts.
255b4c3e9b5SBjoern A. Zeeb  * The MAC addresses in the troublesome nvram files seem to all come from
256b4c3e9b5SBjoern A. Zeeb  * the same nvram file template, so we only need to check for 1 known
257b4c3e9b5SBjoern A. Zeeb  * address to detect this.
258b4c3e9b5SBjoern A. Zeeb  */
259b4c3e9b5SBjoern A. Zeeb static const u8 brcmf_default_mac_address[ETH_ALEN] = {
260b4c3e9b5SBjoern A. Zeeb 	0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38
261b4c3e9b5SBjoern A. Zeeb };
262b4c3e9b5SBjoern A. Zeeb 
brcmf_c_process_cal_blob(struct brcmf_if * ifp)263b4c3e9b5SBjoern A. Zeeb static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)
264b4c3e9b5SBjoern A. Zeeb {
265b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
266b4c3e9b5SBjoern A. Zeeb 	struct brcmf_mp_device *settings = drvr->settings;
267b4c3e9b5SBjoern A. Zeeb 	s32 err;
268b4c3e9b5SBjoern A. Zeeb 
269b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "Enter\n");
270b4c3e9b5SBjoern A. Zeeb 
271b4c3e9b5SBjoern A. Zeeb 	if (!settings->cal_blob || !settings->cal_size)
272b4c3e9b5SBjoern A. Zeeb 		return 0;
273b4c3e9b5SBjoern A. Zeeb 
274b4c3e9b5SBjoern A. Zeeb 	brcmf_info("Calibration blob provided by platform, loading\n");
275b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size,
276b4c3e9b5SBjoern A. Zeeb 				    "calload", "calload_status");
277b4c3e9b5SBjoern A. Zeeb 	return err;
278b4c3e9b5SBjoern A. Zeeb }
279b4c3e9b5SBjoern A. Zeeb 
brcmf_c_preinit_dcmds(struct brcmf_if * ifp)280b4c3e9b5SBjoern A. Zeeb int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
281b4c3e9b5SBjoern A. Zeeb {
282b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = ifp->drvr;
283b4c3e9b5SBjoern A. Zeeb 	struct brcmf_fweh_info *fweh = drvr->fweh;
284b4c3e9b5SBjoern A. Zeeb 	u8 buf[BRCMF_DCMD_SMLEN];
285b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus;
286b4c3e9b5SBjoern A. Zeeb 	struct brcmf_rev_info_le revinfo;
287b4c3e9b5SBjoern A. Zeeb 	struct brcmf_rev_info *ri;
288b4c3e9b5SBjoern A. Zeeb 	char *clmver;
289b4c3e9b5SBjoern A. Zeeb 	char *ptr;
290b4c3e9b5SBjoern A. Zeeb 	s32 err;
291b4c3e9b5SBjoern A. Zeeb 
292b4c3e9b5SBjoern A. Zeeb 	if (is_valid_ether_addr(ifp->mac_addr)) {
293b4c3e9b5SBjoern A. Zeeb 		/* set mac address */
294b4c3e9b5SBjoern A. Zeeb 		err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
295b4c3e9b5SBjoern A. Zeeb 		if (err < 0)
296b4c3e9b5SBjoern A. Zeeb 			goto done;
297b4c3e9b5SBjoern A. Zeeb 	} else {
298b4c3e9b5SBjoern A. Zeeb 		/* retrieve mac address */
299b4c3e9b5SBjoern A. Zeeb 		err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
300b4c3e9b5SBjoern A. Zeeb 					       sizeof(ifp->mac_addr));
301b4c3e9b5SBjoern A. Zeeb 		if (err < 0) {
302b4c3e9b5SBjoern A. Zeeb 			bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
303b4c3e9b5SBjoern A. Zeeb 			goto done;
304b4c3e9b5SBjoern A. Zeeb 		}
305b4c3e9b5SBjoern A. Zeeb 
306b4c3e9b5SBjoern A. Zeeb 		if (ether_addr_equal_unaligned(ifp->mac_addr, brcmf_default_mac_address)) {
307b4c3e9b5SBjoern A. Zeeb 			bphy_err(drvr, "Default MAC is used, replacing with random MAC to avoid conflicts\n");
308b4c3e9b5SBjoern A. Zeeb 			eth_random_addr(ifp->mac_addr);
309b4c3e9b5SBjoern A. Zeeb 			ifp->ndev->addr_assign_type = NET_ADDR_RANDOM;
310b4c3e9b5SBjoern A. Zeeb 			err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
311b4c3e9b5SBjoern A. Zeeb 			if (err < 0)
312b4c3e9b5SBjoern A. Zeeb 				goto done;
313b4c3e9b5SBjoern A. Zeeb 		}
314b4c3e9b5SBjoern A. Zeeb 	}
315b4c3e9b5SBjoern A. Zeeb 
316b4c3e9b5SBjoern A. Zeeb 	memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
317b4c3e9b5SBjoern A. Zeeb 	memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
318b4c3e9b5SBjoern A. Zeeb 
319b4c3e9b5SBjoern A. Zeeb 	bus = ifp->drvr->bus_if;
320b4c3e9b5SBjoern A. Zeeb 	ri = &ifp->drvr->revinfo;
321b4c3e9b5SBjoern A. Zeeb 
322b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
323b4c3e9b5SBjoern A. Zeeb 				     &revinfo, sizeof(revinfo));
324b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
325b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "retrieving revision info failed, %d\n", err);
326b4c3e9b5SBjoern A. Zeeb 		strscpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
327b4c3e9b5SBjoern A. Zeeb 	} else {
328b4c3e9b5SBjoern A. Zeeb 		ri->vendorid = le32_to_cpu(revinfo.vendorid);
329b4c3e9b5SBjoern A. Zeeb 		ri->deviceid = le32_to_cpu(revinfo.deviceid);
330b4c3e9b5SBjoern A. Zeeb 		ri->radiorev = le32_to_cpu(revinfo.radiorev);
331b4c3e9b5SBjoern A. Zeeb 		ri->corerev = le32_to_cpu(revinfo.corerev);
332b4c3e9b5SBjoern A. Zeeb 		ri->boardid = le32_to_cpu(revinfo.boardid);
333b4c3e9b5SBjoern A. Zeeb 		ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
334b4c3e9b5SBjoern A. Zeeb 		ri->boardrev = le32_to_cpu(revinfo.boardrev);
335b4c3e9b5SBjoern A. Zeeb 		ri->driverrev = le32_to_cpu(revinfo.driverrev);
336b4c3e9b5SBjoern A. Zeeb 		ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
337b4c3e9b5SBjoern A. Zeeb 		ri->bus = le32_to_cpu(revinfo.bus);
338b4c3e9b5SBjoern A. Zeeb 		ri->phytype = le32_to_cpu(revinfo.phytype);
339b4c3e9b5SBjoern A. Zeeb 		ri->phyrev = le32_to_cpu(revinfo.phyrev);
340b4c3e9b5SBjoern A. Zeeb 		ri->anarev = le32_to_cpu(revinfo.anarev);
341b4c3e9b5SBjoern A. Zeeb 		ri->chippkg = le32_to_cpu(revinfo.chippkg);
342b4c3e9b5SBjoern A. Zeeb 		ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
343b4c3e9b5SBjoern A. Zeeb 
344b4c3e9b5SBjoern A. Zeeb 		/* use revinfo if not known yet */
345b4c3e9b5SBjoern A. Zeeb 		if (!bus->chip) {
346b4c3e9b5SBjoern A. Zeeb 			bus->chip = le32_to_cpu(revinfo.chipnum);
347b4c3e9b5SBjoern A. Zeeb 			bus->chiprev = le32_to_cpu(revinfo.chiprev);
348b4c3e9b5SBjoern A. Zeeb 		}
349b4c3e9b5SBjoern A. Zeeb 	}
350b4c3e9b5SBjoern A. Zeeb 	ri->result = err;
351b4c3e9b5SBjoern A. Zeeb 
352b4c3e9b5SBjoern A. Zeeb 	if (bus->chip)
353b4c3e9b5SBjoern A. Zeeb 		brcmf_chip_name(bus->chip, bus->chiprev,
354b4c3e9b5SBjoern A. Zeeb 				ri->chipname, sizeof(ri->chipname));
355b4c3e9b5SBjoern A. Zeeb 
356b4c3e9b5SBjoern A. Zeeb 	/* Do any CLM downloading */
357b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_process_clm_blob(ifp);
358b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
359b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "download CLM blob file failed, %d\n", err);
360b4c3e9b5SBjoern A. Zeeb 		goto done;
361b4c3e9b5SBjoern A. Zeeb 	}
362b4c3e9b5SBjoern A. Zeeb 
363b4c3e9b5SBjoern A. Zeeb 	/* Do TxCap downloading, if needed */
364b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_process_txcap_blob(ifp);
365b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
366b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "download TxCap blob file failed, %d\n", err);
367b4c3e9b5SBjoern A. Zeeb 		goto done;
368b4c3e9b5SBjoern A. Zeeb 	}
369b4c3e9b5SBjoern A. Zeeb 
370b4c3e9b5SBjoern A. Zeeb 	/* Download external calibration blob, if available */
371b4c3e9b5SBjoern A. Zeeb 	err = brcmf_c_process_cal_blob(ifp);
372b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
373b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "download calibration blob file failed, %d\n", err);
374b4c3e9b5SBjoern A. Zeeb 		goto done;
375b4c3e9b5SBjoern A. Zeeb 	}
376b4c3e9b5SBjoern A. Zeeb 
377b4c3e9b5SBjoern A. Zeeb 	/* query for 'ver' to get version info from firmware */
378b4c3e9b5SBjoern A. Zeeb 	memset(buf, 0, sizeof(buf));
379b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
380b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
381b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "Retrieving version information failed, %d\n",
382b4c3e9b5SBjoern A. Zeeb 			 err);
383b4c3e9b5SBjoern A. Zeeb 		goto done;
384b4c3e9b5SBjoern A. Zeeb 	}
385b4c3e9b5SBjoern A. Zeeb 	buf[sizeof(buf) - 1] = '\0';
386b4c3e9b5SBjoern A. Zeeb 	ptr = (char *)buf;
387b4c3e9b5SBjoern A. Zeeb 	strsep(&ptr, "\n");
388b4c3e9b5SBjoern A. Zeeb 
389b4c3e9b5SBjoern A. Zeeb 	/* Print fw version info */
390b4c3e9b5SBjoern A. Zeeb 	brcmf_info("Firmware: %s %s\n", ri->chipname, buf);
391b4c3e9b5SBjoern A. Zeeb 
392b4c3e9b5SBjoern A. Zeeb 	/* locate firmware version number for ethtool */
393b4c3e9b5SBjoern A. Zeeb 	ptr = strrchr(buf, ' ');
394b4c3e9b5SBjoern A. Zeeb 	if (!ptr) {
395b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "Retrieving version number failed");
396b4c3e9b5SBjoern A. Zeeb 		goto done;
397b4c3e9b5SBjoern A. Zeeb 	}
398b4c3e9b5SBjoern A. Zeeb 	strscpy(ifp->drvr->fwver, ptr + 1, sizeof(ifp->drvr->fwver));
399b4c3e9b5SBjoern A. Zeeb 
400b4c3e9b5SBjoern A. Zeeb 	/* Query for 'clmver' to get CLM version info from firmware */
401b4c3e9b5SBjoern A. Zeeb 	memset(buf, 0, sizeof(buf));
402b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
403b4c3e9b5SBjoern A. Zeeb 	if (err) {
404b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
405b4c3e9b5SBjoern A. Zeeb 	} else {
406b4c3e9b5SBjoern A. Zeeb 		buf[sizeof(buf) - 1] = '\0';
407b4c3e9b5SBjoern A. Zeeb 		clmver = (char *)buf;
408b4c3e9b5SBjoern A. Zeeb 
409b4c3e9b5SBjoern A. Zeeb 		/* Replace all newline/linefeed characters with space
410b4c3e9b5SBjoern A. Zeeb 		 * character
411b4c3e9b5SBjoern A. Zeeb 		 */
412b4c3e9b5SBjoern A. Zeeb 		strreplace(clmver, '\n', ' ');
413b4c3e9b5SBjoern A. Zeeb 
414b4c3e9b5SBjoern A. Zeeb 		/* store CLM version for adding it to revinfo debugfs file */
415b4c3e9b5SBjoern A. Zeeb 		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
416b4c3e9b5SBjoern A. Zeeb 
417b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(INFO, "CLM version = %s\n", clmver);
418b4c3e9b5SBjoern A. Zeeb 	}
419b4c3e9b5SBjoern A. Zeeb 
420b4c3e9b5SBjoern A. Zeeb 	/* set mpc */
421b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
422b4c3e9b5SBjoern A. Zeeb 	if (err) {
423b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "failed setting mpc\n");
424b4c3e9b5SBjoern A. Zeeb 		goto done;
425b4c3e9b5SBjoern A. Zeeb 	}
426b4c3e9b5SBjoern A. Zeeb 
427b4c3e9b5SBjoern A. Zeeb 	brcmf_c_set_joinpref_default(ifp);
428b4c3e9b5SBjoern A. Zeeb 
429b4c3e9b5SBjoern A. Zeeb 	/* Setup event_msgs, enable E_IF */
430b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_get(ifp, "event_msgs", fweh->event_mask,
431b4c3e9b5SBjoern A. Zeeb 				       fweh->event_mask_len);
432b4c3e9b5SBjoern A. Zeeb 	if (err) {
433b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "Get event_msgs error (%d)\n", err);
434b4c3e9b5SBjoern A. Zeeb 		goto done;
435b4c3e9b5SBjoern A. Zeeb 	}
436b4c3e9b5SBjoern A. Zeeb 	/*
437b4c3e9b5SBjoern A. Zeeb 	 * BRCMF_E_IF can safely be used to set the appropriate bit
438b4c3e9b5SBjoern A. Zeeb 	 * in the event_mask as the firmware event code is guaranteed
439b4c3e9b5SBjoern A. Zeeb 	 * to match the value of BRCMF_E_IF because it is old cruft
440b4c3e9b5SBjoern A. Zeeb 	 * that all vendors have.
441b4c3e9b5SBjoern A. Zeeb 	 */
442b4c3e9b5SBjoern A. Zeeb 	setbit(fweh->event_mask, BRCMF_E_IF);
443b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask,
444b4c3e9b5SBjoern A. Zeeb 				       fweh->event_mask_len);
445b4c3e9b5SBjoern A. Zeeb 	if (err) {
446b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "Set event_msgs error (%d)\n", err);
447b4c3e9b5SBjoern A. Zeeb 		goto done;
448b4c3e9b5SBjoern A. Zeeb 	}
449b4c3e9b5SBjoern A. Zeeb 
450b4c3e9b5SBjoern A. Zeeb 	/* Setup default scan channel time */
451b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
452b4c3e9b5SBjoern A. Zeeb 				    BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
453b4c3e9b5SBjoern A. Zeeb 	if (err) {
454b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
455b4c3e9b5SBjoern A. Zeeb 			 err);
456b4c3e9b5SBjoern A. Zeeb 		goto done;
457b4c3e9b5SBjoern A. Zeeb 	}
458b4c3e9b5SBjoern A. Zeeb 
459b4c3e9b5SBjoern A. Zeeb 	/* Setup default scan unassoc time */
460b4c3e9b5SBjoern A. Zeeb 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
461b4c3e9b5SBjoern A. Zeeb 				    BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
462b4c3e9b5SBjoern A. Zeeb 	if (err) {
463b4c3e9b5SBjoern A. Zeeb 		bphy_err(drvr, "BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
464b4c3e9b5SBjoern A. Zeeb 			 err);
465b4c3e9b5SBjoern A. Zeeb 		goto done;
466b4c3e9b5SBjoern A. Zeeb 	}
467b4c3e9b5SBjoern A. Zeeb 
468b4c3e9b5SBjoern A. Zeeb 	/* Enable tx beamforming, errors can be ignored (not supported) */
469b4c3e9b5SBjoern A. Zeeb 	(void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
470b4c3e9b5SBjoern A. Zeeb done:
471b4c3e9b5SBjoern A. Zeeb 	return err;
472b4c3e9b5SBjoern A. Zeeb }
473b4c3e9b5SBjoern A. Zeeb 
474b4c3e9b5SBjoern A. Zeeb #ifndef CONFIG_BRCM_TRACING
__brcmf_err(struct brcmf_bus * bus,const char * func,const char * fmt,...)475b4c3e9b5SBjoern A. Zeeb void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...)
476b4c3e9b5SBjoern A. Zeeb {
477b4c3e9b5SBjoern A. Zeeb 	struct va_format vaf;
478b4c3e9b5SBjoern A. Zeeb 	va_list args;
479b4c3e9b5SBjoern A. Zeeb 
480b4c3e9b5SBjoern A. Zeeb 	va_start(args, fmt);
481b4c3e9b5SBjoern A. Zeeb 
482b4c3e9b5SBjoern A. Zeeb 	vaf.fmt = fmt;
483b4c3e9b5SBjoern A. Zeeb 	vaf.va = &args;
484*902136e0SBjoern A. Zeeb #if defined(__linux__)
485b4c3e9b5SBjoern A. Zeeb 	if (bus)
486b4c3e9b5SBjoern A. Zeeb 		dev_err(bus->dev, "%s: %pV", func, &vaf);
487b4c3e9b5SBjoern A. Zeeb 	else
488b4c3e9b5SBjoern A. Zeeb 		pr_err("%s: %pV", func, &vaf);
489*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
490*902136e0SBjoern A. Zeeb 	{
491*902136e0SBjoern A. Zeeb 	char *str;
492*902136e0SBjoern A. Zeeb 	vasprintf(&str, M_KMALLOC, vaf.fmt, args);
493*902136e0SBjoern A. Zeeb 	if (bus)
494*902136e0SBjoern A. Zeeb 		dev_err(bus->dev, "ERROR: %s: %s", func, str);
495*902136e0SBjoern A. Zeeb 	else
496*902136e0SBjoern A. Zeeb 		pr_err("ERROR: %s: %s", func, str);
497*902136e0SBjoern A. Zeeb 	free(str, M_KMALLOC);
498*902136e0SBjoern A. Zeeb 	}
499*902136e0SBjoern A. Zeeb #endif
500b4c3e9b5SBjoern A. Zeeb 
501b4c3e9b5SBjoern A. Zeeb 	va_end(args);
502b4c3e9b5SBjoern A. Zeeb }
503b4c3e9b5SBjoern A. Zeeb #endif
504b4c3e9b5SBjoern A. Zeeb 
505b4c3e9b5SBjoern A. Zeeb #if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
__brcmf_dbg(u32 level,const char * func,const char * fmt,...)506b4c3e9b5SBjoern A. Zeeb void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
507b4c3e9b5SBjoern A. Zeeb {
508b4c3e9b5SBjoern A. Zeeb 	struct va_format vaf = {
509b4c3e9b5SBjoern A. Zeeb 		.fmt = fmt,
510b4c3e9b5SBjoern A. Zeeb 	};
511b4c3e9b5SBjoern A. Zeeb 	va_list args;
512b4c3e9b5SBjoern A. Zeeb 
513b4c3e9b5SBjoern A. Zeeb 	va_start(args, fmt);
514b4c3e9b5SBjoern A. Zeeb 	vaf.va = &args;
515b4c3e9b5SBjoern A. Zeeb 	if (brcmf_msg_level & level)
516*902136e0SBjoern A. Zeeb #if defined(__linux__)
517b4c3e9b5SBjoern A. Zeeb 		pr_debug("%s %pV", func, &vaf);
518*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
519*902136e0SBjoern A. Zeeb 	{
520*902136e0SBjoern A. Zeeb 		char *str;
521*902136e0SBjoern A. Zeeb 		vasprintf(&str, M_KMALLOC, vaf.fmt, args);
522*902136e0SBjoern A. Zeeb 		pr_debug("%s %s", func, str);
523*902136e0SBjoern A. Zeeb 		free(str, M_KMALLOC);
524*902136e0SBjoern A. Zeeb 	}
525*902136e0SBjoern A. Zeeb #endif
526b4c3e9b5SBjoern A. Zeeb 	trace_brcmf_dbg(level, func, &vaf);
527b4c3e9b5SBjoern A. Zeeb 	va_end(args);
528b4c3e9b5SBjoern A. Zeeb }
529b4c3e9b5SBjoern A. Zeeb BRCMF_EXPORT_SYMBOL_GPL(__brcmf_dbg);
530b4c3e9b5SBjoern A. Zeeb #endif
531b4c3e9b5SBjoern A. Zeeb 
brcmf_mp_attach(void)532b4c3e9b5SBjoern A. Zeeb static void brcmf_mp_attach(void)
533b4c3e9b5SBjoern A. Zeeb {
534b4c3e9b5SBjoern A. Zeeb 	/* If module param firmware path is set then this will always be used,
535b4c3e9b5SBjoern A. Zeeb 	 * if not set then if available use the platform data version. To make
536b4c3e9b5SBjoern A. Zeeb 	 * sure it gets initialized at all, always copy the module param version
537b4c3e9b5SBjoern A. Zeeb 	 */
538b4c3e9b5SBjoern A. Zeeb 	strscpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
539b4c3e9b5SBjoern A. Zeeb 		BRCMF_FW_ALTPATH_LEN);
540b4c3e9b5SBjoern A. Zeeb 	if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
541b4c3e9b5SBjoern A. Zeeb 	    (brcmf_mp_global.firmware_path[0] == '\0')) {
542b4c3e9b5SBjoern A. Zeeb 		strscpy(brcmf_mp_global.firmware_path,
543b4c3e9b5SBjoern A. Zeeb 			brcmfmac_pdata->fw_alternative_path,
544b4c3e9b5SBjoern A. Zeeb 			BRCMF_FW_ALTPATH_LEN);
545b4c3e9b5SBjoern A. Zeeb 	}
546b4c3e9b5SBjoern A. Zeeb }
547b4c3e9b5SBjoern A. Zeeb 
brcmf_get_module_param(struct device * dev,enum brcmf_bus_type bus_type,u32 chip,u32 chiprev)548b4c3e9b5SBjoern A. Zeeb struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
549b4c3e9b5SBjoern A. Zeeb 					       enum brcmf_bus_type bus_type,
550b4c3e9b5SBjoern A. Zeeb 					       u32 chip, u32 chiprev)
551b4c3e9b5SBjoern A. Zeeb {
552b4c3e9b5SBjoern A. Zeeb 	struct brcmf_mp_device *settings;
553b4c3e9b5SBjoern A. Zeeb 	struct brcmfmac_pd_device *device_pd;
554b4c3e9b5SBjoern A. Zeeb 	bool found;
555b4c3e9b5SBjoern A. Zeeb 	int i;
556b4c3e9b5SBjoern A. Zeeb 
557b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
558b4c3e9b5SBjoern A. Zeeb 		  chiprev);
559b4c3e9b5SBjoern A. Zeeb 	settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
560b4c3e9b5SBjoern A. Zeeb 	if (!settings)
561b4c3e9b5SBjoern A. Zeeb 		return NULL;
562b4c3e9b5SBjoern A. Zeeb 
563b4c3e9b5SBjoern A. Zeeb 	/* start by using the module parameters */
564b4c3e9b5SBjoern A. Zeeb 	settings->p2p_enable = !!brcmf_p2p_enable;
565b4c3e9b5SBjoern A. Zeeb 	settings->feature_disable = brcmf_feature_disable;
566b4c3e9b5SBjoern A. Zeeb 	settings->fcmode = brcmf_fcmode;
567b4c3e9b5SBjoern A. Zeeb 	settings->roamoff = !!brcmf_roamoff;
568b4c3e9b5SBjoern A. Zeeb 	settings->iapp = !!brcmf_iapp_enable;
569b4c3e9b5SBjoern A. Zeeb #ifdef DEBUG
570b4c3e9b5SBjoern A. Zeeb 	settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
571b4c3e9b5SBjoern A. Zeeb #endif
572b4c3e9b5SBjoern A. Zeeb 
573b4c3e9b5SBjoern A. Zeeb 	if (bus_type == BRCMF_BUSTYPE_SDIO)
574b4c3e9b5SBjoern A. Zeeb 		settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
575b4c3e9b5SBjoern A. Zeeb 
576b4c3e9b5SBjoern A. Zeeb 	/* See if there is any device specific platform data configured */
577b4c3e9b5SBjoern A. Zeeb 	found = false;
578b4c3e9b5SBjoern A. Zeeb 	if (brcmfmac_pdata) {
579b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < brcmfmac_pdata->device_count; i++) {
580b4c3e9b5SBjoern A. Zeeb 			device_pd = &brcmfmac_pdata->devices[i];
581b4c3e9b5SBjoern A. Zeeb 			if ((device_pd->bus_type == bus_type) &&
582b4c3e9b5SBjoern A. Zeeb 			    (device_pd->id == chip) &&
583b4c3e9b5SBjoern A. Zeeb 			    ((device_pd->rev == chiprev) ||
584b4c3e9b5SBjoern A. Zeeb 			     (device_pd->rev == -1))) {
585b4c3e9b5SBjoern A. Zeeb 				brcmf_dbg(INFO, "Platform data for device found\n");
586b4c3e9b5SBjoern A. Zeeb 				settings->country_codes =
587b4c3e9b5SBjoern A. Zeeb 						device_pd->country_codes;
588b4c3e9b5SBjoern A. Zeeb 				if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
589b4c3e9b5SBjoern A. Zeeb 					memcpy(&settings->bus.sdio,
590b4c3e9b5SBjoern A. Zeeb 					       &device_pd->bus.sdio,
591b4c3e9b5SBjoern A. Zeeb 					       sizeof(settings->bus.sdio));
592b4c3e9b5SBjoern A. Zeeb 				found = true;
593b4c3e9b5SBjoern A. Zeeb 				break;
594b4c3e9b5SBjoern A. Zeeb 			}
595b4c3e9b5SBjoern A. Zeeb 		}
596b4c3e9b5SBjoern A. Zeeb 	}
597b4c3e9b5SBjoern A. Zeeb 	if (!found) {
598b4c3e9b5SBjoern A. Zeeb 		/* No platform data for this device, try OF and DMI data */
599b4c3e9b5SBjoern A. Zeeb 		brcmf_dmi_probe(settings, chip, chiprev);
600b4c3e9b5SBjoern A. Zeeb 		if (brcmf_of_probe(dev, bus_type, settings) == -EPROBE_DEFER) {
601b4c3e9b5SBjoern A. Zeeb 			kfree(settings);
602b4c3e9b5SBjoern A. Zeeb 			return ERR_PTR(-EPROBE_DEFER);
603b4c3e9b5SBjoern A. Zeeb 		}
604b4c3e9b5SBjoern A. Zeeb 		brcmf_acpi_probe(dev, bus_type, settings);
605b4c3e9b5SBjoern A. Zeeb 	}
606b4c3e9b5SBjoern A. Zeeb 	return settings;
607b4c3e9b5SBjoern A. Zeeb }
608b4c3e9b5SBjoern A. Zeeb 
brcmf_release_module_param(struct brcmf_mp_device * module_param)609b4c3e9b5SBjoern A. Zeeb void brcmf_release_module_param(struct brcmf_mp_device *module_param)
610b4c3e9b5SBjoern A. Zeeb {
611b4c3e9b5SBjoern A. Zeeb 	kfree(module_param);
612b4c3e9b5SBjoern A. Zeeb }
613b4c3e9b5SBjoern A. Zeeb 
brcmf_common_pd_probe(struct platform_device * pdev)614b4c3e9b5SBjoern A. Zeeb static int __init brcmf_common_pd_probe(struct platform_device *pdev)
615b4c3e9b5SBjoern A. Zeeb {
616b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(INFO, "Enter\n");
617b4c3e9b5SBjoern A. Zeeb 
618b4c3e9b5SBjoern A. Zeeb 	brcmfmac_pdata = dev_get_platdata(&pdev->dev);
619b4c3e9b5SBjoern A. Zeeb 
620b4c3e9b5SBjoern A. Zeeb 	if (brcmfmac_pdata->power_on)
621b4c3e9b5SBjoern A. Zeeb 		brcmfmac_pdata->power_on();
622b4c3e9b5SBjoern A. Zeeb 
623b4c3e9b5SBjoern A. Zeeb 	return 0;
624b4c3e9b5SBjoern A. Zeeb }
625b4c3e9b5SBjoern A. Zeeb 
brcmf_common_pd_remove(struct platform_device * pdev)626b4c3e9b5SBjoern A. Zeeb static void brcmf_common_pd_remove(struct platform_device *pdev)
627b4c3e9b5SBjoern A. Zeeb {
628b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(INFO, "Enter\n");
629b4c3e9b5SBjoern A. Zeeb 
630b4c3e9b5SBjoern A. Zeeb 	if (brcmfmac_pdata->power_off)
631b4c3e9b5SBjoern A. Zeeb 		brcmfmac_pdata->power_off();
632b4c3e9b5SBjoern A. Zeeb }
633b4c3e9b5SBjoern A. Zeeb 
634b4c3e9b5SBjoern A. Zeeb static struct platform_driver brcmf_pd = {
635b4c3e9b5SBjoern A. Zeeb 	.remove		= brcmf_common_pd_remove,
636b4c3e9b5SBjoern A. Zeeb 	.driver		= {
637b4c3e9b5SBjoern A. Zeeb 		.name	= BRCMFMAC_PDATA_NAME,
638b4c3e9b5SBjoern A. Zeeb 	}
639b4c3e9b5SBjoern A. Zeeb };
640b4c3e9b5SBjoern A. Zeeb 
brcmfmac_module_init(void)641b4c3e9b5SBjoern A. Zeeb static int __init brcmfmac_module_init(void)
642b4c3e9b5SBjoern A. Zeeb {
643b4c3e9b5SBjoern A. Zeeb 	int err;
644b4c3e9b5SBjoern A. Zeeb 
645b4c3e9b5SBjoern A. Zeeb 	/* Get the platform data (if available) for our devices */
646b4c3e9b5SBjoern A. Zeeb 	err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
647b4c3e9b5SBjoern A. Zeeb 	if (err == -ENODEV)
648b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(INFO, "No platform data available.\n");
649b4c3e9b5SBjoern A. Zeeb 
650b4c3e9b5SBjoern A. Zeeb 	/* Initialize global module parameters */
651b4c3e9b5SBjoern A. Zeeb 	brcmf_mp_attach();
652b4c3e9b5SBjoern A. Zeeb 
653b4c3e9b5SBjoern A. Zeeb 	/* Continue the initialization by registering the different busses */
654b4c3e9b5SBjoern A. Zeeb 	err = brcmf_core_init();
655b4c3e9b5SBjoern A. Zeeb 	if (err) {
656b4c3e9b5SBjoern A. Zeeb 		if (brcmfmac_pdata)
657b4c3e9b5SBjoern A. Zeeb 			platform_driver_unregister(&brcmf_pd);
658b4c3e9b5SBjoern A. Zeeb 	}
659b4c3e9b5SBjoern A. Zeeb 
660b4c3e9b5SBjoern A. Zeeb 	return err;
661b4c3e9b5SBjoern A. Zeeb }
662b4c3e9b5SBjoern A. Zeeb 
brcmfmac_module_exit(void)663b4c3e9b5SBjoern A. Zeeb static void __exit brcmfmac_module_exit(void)
664b4c3e9b5SBjoern A. Zeeb {
665b4c3e9b5SBjoern A. Zeeb 	brcmf_core_exit();
666b4c3e9b5SBjoern A. Zeeb 	if (brcmfmac_pdata)
667b4c3e9b5SBjoern A. Zeeb 		platform_driver_unregister(&brcmf_pd);
668b4c3e9b5SBjoern A. Zeeb }
669b4c3e9b5SBjoern A. Zeeb 
670b4c3e9b5SBjoern A. Zeeb module_init(brcmfmac_module_init);
671b4c3e9b5SBjoern A. Zeeb module_exit(brcmfmac_module_exit);
672b4c3e9b5SBjoern A. Zeeb 
673