xref: /openbmc/linux/drivers/net/wireless/st/cw1200/main.c (revision a790cc3a)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2560424e9SKalle Valo /*
3560424e9SKalle Valo  * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
4560424e9SKalle Valo  *
5560424e9SKalle Valo  * Copyright (c) 2010, ST-Ericsson
6560424e9SKalle Valo  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
7560424e9SKalle Valo  *
8560424e9SKalle Valo  * Based on:
9560424e9SKalle Valo  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
10560424e9SKalle Valo  * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
11560424e9SKalle Valo  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
12560424e9SKalle Valo  *
13560424e9SKalle Valo  * Based on:
14560424e9SKalle Valo  * - the islsm (softmac prism54) driver, which is:
15560424e9SKalle Valo  *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
16560424e9SKalle Valo  * - stlc45xx driver
17560424e9SKalle Valo  *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
18560424e9SKalle Valo  */
19560424e9SKalle Valo 
20560424e9SKalle Valo #include <linux/module.h>
21560424e9SKalle Valo #include <linux/firmware.h>
22560424e9SKalle Valo #include <linux/etherdevice.h>
23560424e9SKalle Valo #include <linux/vmalloc.h>
24560424e9SKalle Valo #include <linux/random.h>
25560424e9SKalle Valo #include <linux/sched.h>
26560424e9SKalle Valo #include <net/mac80211.h>
27560424e9SKalle Valo 
28560424e9SKalle Valo #include "cw1200.h"
29560424e9SKalle Valo #include "txrx.h"
30560424e9SKalle Valo #include "hwbus.h"
31560424e9SKalle Valo #include "fwio.h"
32560424e9SKalle Valo #include "hwio.h"
33560424e9SKalle Valo #include "bh.h"
34560424e9SKalle Valo #include "sta.h"
35560424e9SKalle Valo #include "scan.h"
36560424e9SKalle Valo #include "debug.h"
37560424e9SKalle Valo #include "pm.h"
38560424e9SKalle Valo 
39560424e9SKalle Valo MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
40560424e9SKalle Valo MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code");
41560424e9SKalle Valo MODULE_LICENSE("GPL");
42560424e9SKalle Valo MODULE_ALIAS("cw1200_core");
43560424e9SKalle Valo 
44560424e9SKalle Valo /* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
45560424e9SKalle Valo static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
462ef00c53SJoe Perches module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444);
47560424e9SKalle Valo MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
48560424e9SKalle Valo 
49560424e9SKalle Valo static char *cw1200_sdd_path;
50560424e9SKalle Valo module_param(cw1200_sdd_path, charp, 0644);
51560424e9SKalle Valo MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file");
52560424e9SKalle Valo static int cw1200_refclk;
53560424e9SKalle Valo module_param(cw1200_refclk, int, 0644);
54560424e9SKalle Valo MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock");
55560424e9SKalle Valo 
56560424e9SKalle Valo int cw1200_power_mode = wsm_power_mode_quiescent;
57560424e9SKalle Valo module_param(cw1200_power_mode, int, 0644);
58560424e9SKalle Valo MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode.  0 == active, 1 == doze, 2 == quiescent (default)");
59560424e9SKalle Valo 
60560424e9SKalle Valo #define RATETAB_ENT(_rate, _rateid, _flags)		\
61560424e9SKalle Valo 	{						\
62560424e9SKalle Valo 		.bitrate	= (_rate),		\
63560424e9SKalle Valo 		.hw_value	= (_rateid),		\
64560424e9SKalle Valo 		.flags		= (_flags),		\
65560424e9SKalle Valo 	}
66560424e9SKalle Valo 
67560424e9SKalle Valo static struct ieee80211_rate cw1200_rates[] = {
68560424e9SKalle Valo 	RATETAB_ENT(10,  0,   0),
69560424e9SKalle Valo 	RATETAB_ENT(20,  1,   0),
70560424e9SKalle Valo 	RATETAB_ENT(55,  2,   0),
71560424e9SKalle Valo 	RATETAB_ENT(110, 3,   0),
72560424e9SKalle Valo 	RATETAB_ENT(60,  6,  0),
73560424e9SKalle Valo 	RATETAB_ENT(90,  7,  0),
74560424e9SKalle Valo 	RATETAB_ENT(120, 8,  0),
75560424e9SKalle Valo 	RATETAB_ENT(180, 9,  0),
76560424e9SKalle Valo 	RATETAB_ENT(240, 10, 0),
77560424e9SKalle Valo 	RATETAB_ENT(360, 11, 0),
78560424e9SKalle Valo 	RATETAB_ENT(480, 12, 0),
79560424e9SKalle Valo 	RATETAB_ENT(540, 13, 0),
80560424e9SKalle Valo };
81560424e9SKalle Valo 
82560424e9SKalle Valo static struct ieee80211_rate cw1200_mcs_rates[] = {
83560424e9SKalle Valo 	RATETAB_ENT(65,  14, IEEE80211_TX_RC_MCS),
84560424e9SKalle Valo 	RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
85560424e9SKalle Valo 	RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
86560424e9SKalle Valo 	RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
87560424e9SKalle Valo 	RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
88560424e9SKalle Valo 	RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
89560424e9SKalle Valo 	RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
90560424e9SKalle Valo 	RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
91560424e9SKalle Valo };
92560424e9SKalle Valo 
93560424e9SKalle Valo #define cw1200_a_rates		(cw1200_rates + 4)
94560424e9SKalle Valo #define cw1200_a_rates_size	(ARRAY_SIZE(cw1200_rates) - 4)
95560424e9SKalle Valo #define cw1200_g_rates		(cw1200_rates + 0)
96560424e9SKalle Valo #define cw1200_g_rates_size	(ARRAY_SIZE(cw1200_rates))
97560424e9SKalle Valo #define cw1200_n_rates		(cw1200_mcs_rates)
98560424e9SKalle Valo #define cw1200_n_rates_size	(ARRAY_SIZE(cw1200_mcs_rates))
99560424e9SKalle Valo 
100560424e9SKalle Valo 
101560424e9SKalle Valo #define CHAN2G(_channel, _freq, _flags) {			\
10257fbcce3SJohannes Berg 	.band			= NL80211_BAND_2GHZ,		\
103560424e9SKalle Valo 	.center_freq		= (_freq),			\
104560424e9SKalle Valo 	.hw_value		= (_channel),			\
105560424e9SKalle Valo 	.flags			= (_flags),			\
106560424e9SKalle Valo 	.max_antenna_gain	= 0,				\
107560424e9SKalle Valo 	.max_power		= 30,				\
108560424e9SKalle Valo }
109560424e9SKalle Valo 
110560424e9SKalle Valo #define CHAN5G(_channel, _flags) {				\
11157fbcce3SJohannes Berg 	.band			= NL80211_BAND_5GHZ,		\
112560424e9SKalle Valo 	.center_freq	= 5000 + (5 * (_channel)),		\
113560424e9SKalle Valo 	.hw_value		= (_channel),			\
114560424e9SKalle Valo 	.flags			= (_flags),			\
115560424e9SKalle Valo 	.max_antenna_gain	= 0,				\
116560424e9SKalle Valo 	.max_power		= 30,				\
117560424e9SKalle Valo }
118560424e9SKalle Valo 
119560424e9SKalle Valo static struct ieee80211_channel cw1200_2ghz_chantable[] = {
120560424e9SKalle Valo 	CHAN2G(1, 2412, 0),
121560424e9SKalle Valo 	CHAN2G(2, 2417, 0),
122560424e9SKalle Valo 	CHAN2G(3, 2422, 0),
123560424e9SKalle Valo 	CHAN2G(4, 2427, 0),
124560424e9SKalle Valo 	CHAN2G(5, 2432, 0),
125560424e9SKalle Valo 	CHAN2G(6, 2437, 0),
126560424e9SKalle Valo 	CHAN2G(7, 2442, 0),
127560424e9SKalle Valo 	CHAN2G(8, 2447, 0),
128560424e9SKalle Valo 	CHAN2G(9, 2452, 0),
129560424e9SKalle Valo 	CHAN2G(10, 2457, 0),
130560424e9SKalle Valo 	CHAN2G(11, 2462, 0),
131560424e9SKalle Valo 	CHAN2G(12, 2467, 0),
132560424e9SKalle Valo 	CHAN2G(13, 2472, 0),
133560424e9SKalle Valo 	CHAN2G(14, 2484, 0),
134560424e9SKalle Valo };
135560424e9SKalle Valo 
136560424e9SKalle Valo static struct ieee80211_channel cw1200_5ghz_chantable[] = {
137560424e9SKalle Valo 	CHAN5G(34, 0),		CHAN5G(36, 0),
138560424e9SKalle Valo 	CHAN5G(38, 0),		CHAN5G(40, 0),
139560424e9SKalle Valo 	CHAN5G(42, 0),		CHAN5G(44, 0),
140560424e9SKalle Valo 	CHAN5G(46, 0),		CHAN5G(48, 0),
141560424e9SKalle Valo 	CHAN5G(52, 0),		CHAN5G(56, 0),
142560424e9SKalle Valo 	CHAN5G(60, 0),		CHAN5G(64, 0),
143560424e9SKalle Valo 	CHAN5G(100, 0),		CHAN5G(104, 0),
144560424e9SKalle Valo 	CHAN5G(108, 0),		CHAN5G(112, 0),
145560424e9SKalle Valo 	CHAN5G(116, 0),		CHAN5G(120, 0),
146560424e9SKalle Valo 	CHAN5G(124, 0),		CHAN5G(128, 0),
147560424e9SKalle Valo 	CHAN5G(132, 0),		CHAN5G(136, 0),
148560424e9SKalle Valo 	CHAN5G(140, 0),		CHAN5G(149, 0),
149560424e9SKalle Valo 	CHAN5G(153, 0),		CHAN5G(157, 0),
150560424e9SKalle Valo 	CHAN5G(161, 0),		CHAN5G(165, 0),
151560424e9SKalle Valo 	CHAN5G(184, 0),		CHAN5G(188, 0),
152560424e9SKalle Valo 	CHAN5G(192, 0),		CHAN5G(196, 0),
153560424e9SKalle Valo 	CHAN5G(200, 0),		CHAN5G(204, 0),
154560424e9SKalle Valo 	CHAN5G(208, 0),		CHAN5G(212, 0),
155560424e9SKalle Valo 	CHAN5G(216, 0),
156560424e9SKalle Valo };
157560424e9SKalle Valo 
158560424e9SKalle Valo static struct ieee80211_supported_band cw1200_band_2ghz = {
159560424e9SKalle Valo 	.channels = cw1200_2ghz_chantable,
160560424e9SKalle Valo 	.n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
161560424e9SKalle Valo 	.bitrates = cw1200_g_rates,
162560424e9SKalle Valo 	.n_bitrates = cw1200_g_rates_size,
163560424e9SKalle Valo 	.ht_cap = {
164560424e9SKalle Valo 		.cap = IEEE80211_HT_CAP_GRN_FLD |
165560424e9SKalle Valo 			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
166560424e9SKalle Valo 			IEEE80211_HT_CAP_MAX_AMSDU,
167560424e9SKalle Valo 		.ht_supported = 1,
168560424e9SKalle Valo 		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
169560424e9SKalle Valo 		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
170560424e9SKalle Valo 		.mcs = {
171560424e9SKalle Valo 			.rx_mask[0] = 0xFF,
172560424e9SKalle Valo 			.rx_highest = __cpu_to_le16(0x41),
173560424e9SKalle Valo 			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
174560424e9SKalle Valo 		},
175560424e9SKalle Valo 	},
176560424e9SKalle Valo };
177560424e9SKalle Valo 
178560424e9SKalle Valo static struct ieee80211_supported_band cw1200_band_5ghz = {
179560424e9SKalle Valo 	.channels = cw1200_5ghz_chantable,
180560424e9SKalle Valo 	.n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
181560424e9SKalle Valo 	.bitrates = cw1200_a_rates,
182560424e9SKalle Valo 	.n_bitrates = cw1200_a_rates_size,
183560424e9SKalle Valo 	.ht_cap = {
184560424e9SKalle Valo 		.cap = IEEE80211_HT_CAP_GRN_FLD |
185560424e9SKalle Valo 			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
186560424e9SKalle Valo 			IEEE80211_HT_CAP_MAX_AMSDU,
187560424e9SKalle Valo 		.ht_supported = 1,
188560424e9SKalle Valo 		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
189560424e9SKalle Valo 		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
190560424e9SKalle Valo 		.mcs = {
191560424e9SKalle Valo 			.rx_mask[0] = 0xFF,
192560424e9SKalle Valo 			.rx_highest = __cpu_to_le16(0x41),
193560424e9SKalle Valo 			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
194560424e9SKalle Valo 		},
195560424e9SKalle Valo 	},
196560424e9SKalle Valo };
197560424e9SKalle Valo 
198560424e9SKalle Valo static const unsigned long cw1200_ttl[] = {
199560424e9SKalle Valo 	1 * HZ,	/* VO */
200560424e9SKalle Valo 	2 * HZ,	/* VI */
201560424e9SKalle Valo 	5 * HZ, /* BE */
202560424e9SKalle Valo 	10 * HZ	/* BK */
203560424e9SKalle Valo };
204560424e9SKalle Valo 
205560424e9SKalle Valo static const struct ieee80211_ops cw1200_ops = {
206560424e9SKalle Valo 	.start			= cw1200_start,
207560424e9SKalle Valo 	.stop			= cw1200_stop,
208560424e9SKalle Valo 	.add_interface		= cw1200_add_interface,
209560424e9SKalle Valo 	.remove_interface	= cw1200_remove_interface,
210560424e9SKalle Valo 	.change_interface	= cw1200_change_interface,
211560424e9SKalle Valo 	.tx			= cw1200_tx,
212*a790cc3aSAlexander Wetzel 	.wake_tx_queue		= ieee80211_handle_wake_tx_queue,
213560424e9SKalle Valo 	.hw_scan		= cw1200_hw_scan,
214560424e9SKalle Valo 	.set_tim		= cw1200_set_tim,
215560424e9SKalle Valo 	.sta_notify		= cw1200_sta_notify,
216560424e9SKalle Valo 	.sta_add		= cw1200_sta_add,
217560424e9SKalle Valo 	.sta_remove		= cw1200_sta_remove,
218560424e9SKalle Valo 	.set_key		= cw1200_set_key,
219560424e9SKalle Valo 	.set_rts_threshold	= cw1200_set_rts_threshold,
220560424e9SKalle Valo 	.config			= cw1200_config,
221560424e9SKalle Valo 	.bss_info_changed	= cw1200_bss_info_changed,
222560424e9SKalle Valo 	.prepare_multicast	= cw1200_prepare_multicast,
223560424e9SKalle Valo 	.configure_filter	= cw1200_configure_filter,
224560424e9SKalle Valo 	.conf_tx		= cw1200_conf_tx,
225560424e9SKalle Valo 	.get_stats		= cw1200_get_stats,
226560424e9SKalle Valo 	.ampdu_action		= cw1200_ampdu_action,
227560424e9SKalle Valo 	.flush			= cw1200_flush,
228560424e9SKalle Valo #ifdef CONFIG_PM
229560424e9SKalle Valo 	.suspend		= cw1200_wow_suspend,
230560424e9SKalle Valo 	.resume			= cw1200_wow_resume,
231560424e9SKalle Valo #endif
232560424e9SKalle Valo 	/* Intentionally not offloaded:					*/
233560424e9SKalle Valo 	/*.channel_switch	= cw1200_channel_switch,		*/
234560424e9SKalle Valo 	/*.remain_on_channel	= cw1200_remain_on_channel,		*/
235560424e9SKalle Valo 	/*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel,	*/
236560424e9SKalle Valo };
237560424e9SKalle Valo 
238560424e9SKalle Valo static int cw1200_ba_rx_tids = -1;
239560424e9SKalle Valo static int cw1200_ba_tx_tids = -1;
240560424e9SKalle Valo module_param(cw1200_ba_rx_tids, int, 0644);
241560424e9SKalle Valo module_param(cw1200_ba_tx_tids, int, 0644);
242560424e9SKalle Valo MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
243560424e9SKalle Valo MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
244560424e9SKalle Valo 
245560424e9SKalle Valo #ifdef CONFIG_PM
246560424e9SKalle Valo static const struct wiphy_wowlan_support cw1200_wowlan_support = {
247560424e9SKalle Valo 	/* Support only for limited wowlan functionalities */
248560424e9SKalle Valo 	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
249560424e9SKalle Valo };
250560424e9SKalle Valo #endif
251560424e9SKalle Valo 
252560424e9SKalle Valo 
cw1200_init_common(const u8 * macaddr,const bool have_5ghz)253560424e9SKalle Valo static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
254560424e9SKalle Valo 						const bool have_5ghz)
255560424e9SKalle Valo {
256560424e9SKalle Valo 	int i, band;
257560424e9SKalle Valo 	struct ieee80211_hw *hw;
258560424e9SKalle Valo 	struct cw1200_common *priv;
259560424e9SKalle Valo 
260560424e9SKalle Valo 	hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
261560424e9SKalle Valo 	if (!hw)
262560424e9SKalle Valo 		return NULL;
263560424e9SKalle Valo 
264560424e9SKalle Valo 	priv = hw->priv;
265560424e9SKalle Valo 	priv->hw = hw;
266560424e9SKalle Valo 	priv->hw_type = -1;
267560424e9SKalle Valo 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
268560424e9SKalle Valo 	priv->rates = cw1200_rates; /* TODO: fetch from FW */
269560424e9SKalle Valo 	priv->mcs_rates = cw1200_n_rates;
270560424e9SKalle Valo 	if (cw1200_ba_rx_tids != -1)
271560424e9SKalle Valo 		priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
272560424e9SKalle Valo 	else
273560424e9SKalle Valo 		priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
274560424e9SKalle Valo 	if (cw1200_ba_tx_tids != -1)
275560424e9SKalle Valo 		priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
276560424e9SKalle Valo 	else
277560424e9SKalle Valo 		priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
278560424e9SKalle Valo 
279560424e9SKalle Valo 	ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
280560424e9SKalle Valo 	ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
281560424e9SKalle Valo 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
282560424e9SKalle Valo 	ieee80211_hw_set(hw, CONNECTION_MONITOR);
283560424e9SKalle Valo 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
284560424e9SKalle Valo 	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
285560424e9SKalle Valo 	ieee80211_hw_set(hw, SIGNAL_DBM);
286560424e9SKalle Valo 	ieee80211_hw_set(hw, SUPPORTS_PS);
287560424e9SKalle Valo 
288560424e9SKalle Valo 	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
289560424e9SKalle Valo 					  BIT(NL80211_IFTYPE_ADHOC) |
290560424e9SKalle Valo 					  BIT(NL80211_IFTYPE_AP) |
291560424e9SKalle Valo 					  BIT(NL80211_IFTYPE_MESH_POINT) |
292560424e9SKalle Valo 					  BIT(NL80211_IFTYPE_P2P_CLIENT) |
293560424e9SKalle Valo 					  BIT(NL80211_IFTYPE_P2P_GO);
294560424e9SKalle Valo 
295560424e9SKalle Valo #ifdef CONFIG_PM
296560424e9SKalle Valo 	hw->wiphy->wowlan = &cw1200_wowlan_support;
297560424e9SKalle Valo #endif
298560424e9SKalle Valo 
299560424e9SKalle Valo 	hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
300560424e9SKalle Valo 
301560424e9SKalle Valo 	hw->queues = 4;
302560424e9SKalle Valo 
303560424e9SKalle Valo 	priv->rts_threshold = -1;
304560424e9SKalle Valo 
305560424e9SKalle Valo 	hw->max_rates = 8;
306560424e9SKalle Valo 	hw->max_rate_tries = 15;
307560424e9SKalle Valo 	hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
308560424e9SKalle Valo 		8;  /* TKIP IV */
309560424e9SKalle Valo 
310560424e9SKalle Valo 	hw->sta_data_size = sizeof(struct cw1200_sta_priv);
311560424e9SKalle Valo 
31257fbcce3SJohannes Berg 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &cw1200_band_2ghz;
313560424e9SKalle Valo 	if (have_5ghz)
31457fbcce3SJohannes Berg 		hw->wiphy->bands[NL80211_BAND_5GHZ] = &cw1200_band_5ghz;
315560424e9SKalle Valo 
316560424e9SKalle Valo 	/* Channel params have to be cleared before registering wiphy again */
31757fbcce3SJohannes Berg 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
318560424e9SKalle Valo 		struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
319560424e9SKalle Valo 		if (!sband)
320560424e9SKalle Valo 			continue;
321560424e9SKalle Valo 		for (i = 0; i < sband->n_channels; i++) {
322560424e9SKalle Valo 			sband->channels[i].flags = 0;
323560424e9SKalle Valo 			sband->channels[i].max_antenna_gain = 0;
324560424e9SKalle Valo 			sband->channels[i].max_power = 30;
325560424e9SKalle Valo 		}
326560424e9SKalle Valo 	}
327560424e9SKalle Valo 
328560424e9SKalle Valo 	hw->wiphy->max_scan_ssids = 2;
329560424e9SKalle Valo 	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
330560424e9SKalle Valo 
331560424e9SKalle Valo 	if (macaddr)
332560424e9SKalle Valo 		SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
333560424e9SKalle Valo 	else
334560424e9SKalle Valo 		SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
335560424e9SKalle Valo 
336560424e9SKalle Valo 	/* Fix up mac address if necessary */
337560424e9SKalle Valo 	if (hw->wiphy->perm_addr[3] == 0 &&
338560424e9SKalle Valo 	    hw->wiphy->perm_addr[4] == 0 &&
339560424e9SKalle Valo 	    hw->wiphy->perm_addr[5] == 0) {
340560424e9SKalle Valo 		get_random_bytes(&hw->wiphy->perm_addr[3], 3);
341560424e9SKalle Valo 	}
342560424e9SKalle Valo 
343560424e9SKalle Valo 	mutex_init(&priv->wsm_cmd_mux);
344560424e9SKalle Valo 	mutex_init(&priv->conf_mutex);
345560424e9SKalle Valo 	priv->workqueue = create_singlethread_workqueue("cw1200_wq");
3460ed2a005SKangjie Lu 	if (!priv->workqueue) {
3470ed2a005SKangjie Lu 		ieee80211_free_hw(hw);
3480ed2a005SKangjie Lu 		return NULL;
3490ed2a005SKangjie Lu 	}
3500ed2a005SKangjie Lu 
351560424e9SKalle Valo 	sema_init(&priv->scan.lock, 1);
352560424e9SKalle Valo 	INIT_WORK(&priv->scan.work, cw1200_scan_work);
353560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
354560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
355560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
356560424e9SKalle Valo 			  cw1200_clear_recent_scan_work);
357560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
358560424e9SKalle Valo 	INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
359560424e9SKalle Valo 	INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
360560424e9SKalle Valo 	INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
361560424e9SKalle Valo 	INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
362560424e9SKalle Valo 	spin_lock_init(&priv->event_queue_lock);
363560424e9SKalle Valo 	INIT_LIST_HEAD(&priv->event_queue);
364560424e9SKalle Valo 	INIT_WORK(&priv->event_handler, cw1200_event_handler);
365560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
366560424e9SKalle Valo 	INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
367560424e9SKalle Valo 	spin_lock_init(&priv->bss_loss_lock);
368560424e9SKalle Valo 	spin_lock_init(&priv->ps_state_lock);
369560424e9SKalle Valo 	INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
370560424e9SKalle Valo 	INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
371560424e9SKalle Valo 	INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
372560424e9SKalle Valo 	INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
373560424e9SKalle Valo 	INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
374560424e9SKalle Valo 	INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
375560424e9SKalle Valo 	INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
376560424e9SKalle Valo 	INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
377560424e9SKalle Valo 	INIT_WORK(&priv->set_beacon_wakeup_period_work,
378560424e9SKalle Valo 		  cw1200_set_beacon_wakeup_period_work);
379e3dcf8bbSKees Cook 	timer_setup(&priv->mcast_timeout, cw1200_mcast_timeout, 0);
380560424e9SKalle Valo 
381560424e9SKalle Valo 	if (cw1200_queue_stats_init(&priv->tx_queue_stats,
382560424e9SKalle Valo 				    CW1200_LINK_ID_MAX,
383560424e9SKalle Valo 				    cw1200_skb_dtor,
384560424e9SKalle Valo 				    priv)) {
3857ec8a926SQinglang Miao 		destroy_workqueue(priv->workqueue);
386560424e9SKalle Valo 		ieee80211_free_hw(hw);
387560424e9SKalle Valo 		return NULL;
388560424e9SKalle Valo 	}
389560424e9SKalle Valo 
390560424e9SKalle Valo 	for (i = 0; i < 4; ++i) {
391560424e9SKalle Valo 		if (cw1200_queue_init(&priv->tx_queue[i],
392560424e9SKalle Valo 				      &priv->tx_queue_stats, i, 16,
393560424e9SKalle Valo 				      cw1200_ttl[i])) {
394560424e9SKalle Valo 			for (; i > 0; i--)
395560424e9SKalle Valo 				cw1200_queue_deinit(&priv->tx_queue[i - 1]);
396560424e9SKalle Valo 			cw1200_queue_stats_deinit(&priv->tx_queue_stats);
3977ec8a926SQinglang Miao 			destroy_workqueue(priv->workqueue);
398560424e9SKalle Valo 			ieee80211_free_hw(hw);
399560424e9SKalle Valo 			return NULL;
400560424e9SKalle Valo 		}
401560424e9SKalle Valo 	}
402560424e9SKalle Valo 
403560424e9SKalle Valo 	init_waitqueue_head(&priv->channel_switch_done);
404560424e9SKalle Valo 	init_waitqueue_head(&priv->wsm_cmd_wq);
405560424e9SKalle Valo 	init_waitqueue_head(&priv->wsm_startup_done);
406560424e9SKalle Valo 	init_waitqueue_head(&priv->ps_mode_switch_done);
407560424e9SKalle Valo 	wsm_buf_init(&priv->wsm_cmd_buf);
408560424e9SKalle Valo 	spin_lock_init(&priv->wsm_cmd.lock);
409560424e9SKalle Valo 	priv->wsm_cmd.done = 1;
410560424e9SKalle Valo 	tx_policy_init(priv);
411560424e9SKalle Valo 
412560424e9SKalle Valo 	return hw;
413560424e9SKalle Valo }
414560424e9SKalle Valo 
cw1200_register_common(struct ieee80211_hw * dev)415560424e9SKalle Valo static int cw1200_register_common(struct ieee80211_hw *dev)
416560424e9SKalle Valo {
417560424e9SKalle Valo 	struct cw1200_common *priv = dev->priv;
418560424e9SKalle Valo 	int err;
419560424e9SKalle Valo 
420560424e9SKalle Valo #ifdef CONFIG_PM
421560424e9SKalle Valo 	err = cw1200_pm_init(&priv->pm_state, priv);
422560424e9SKalle Valo 	if (err) {
423560424e9SKalle Valo 		pr_err("Cannot init PM. (%d).\n",
424560424e9SKalle Valo 		       err);
425560424e9SKalle Valo 		return err;
426560424e9SKalle Valo 	}
427560424e9SKalle Valo #endif
428560424e9SKalle Valo 
429560424e9SKalle Valo 	err = ieee80211_register_hw(dev);
430560424e9SKalle Valo 	if (err) {
431560424e9SKalle Valo 		pr_err("Cannot register device (%d).\n",
432560424e9SKalle Valo 		       err);
433560424e9SKalle Valo #ifdef CONFIG_PM
434560424e9SKalle Valo 		cw1200_pm_deinit(&priv->pm_state);
435560424e9SKalle Valo #endif
436560424e9SKalle Valo 		return err;
437560424e9SKalle Valo 	}
438560424e9SKalle Valo 
439560424e9SKalle Valo 	cw1200_debug_init(priv);
440560424e9SKalle Valo 
441560424e9SKalle Valo 	pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
442560424e9SKalle Valo 	return 0;
443560424e9SKalle Valo }
444560424e9SKalle Valo 
cw1200_free_common(struct ieee80211_hw * dev)445560424e9SKalle Valo static void cw1200_free_common(struct ieee80211_hw *dev)
446560424e9SKalle Valo {
447560424e9SKalle Valo 	ieee80211_free_hw(dev);
448560424e9SKalle Valo }
449560424e9SKalle Valo 
cw1200_unregister_common(struct ieee80211_hw * dev)450560424e9SKalle Valo static void cw1200_unregister_common(struct ieee80211_hw *dev)
451560424e9SKalle Valo {
452560424e9SKalle Valo 	struct cw1200_common *priv = dev->priv;
453560424e9SKalle Valo 	int i;
454560424e9SKalle Valo 
455560424e9SKalle Valo 	ieee80211_unregister_hw(dev);
456560424e9SKalle Valo 
457560424e9SKalle Valo 	del_timer_sync(&priv->mcast_timeout);
458560424e9SKalle Valo 	cw1200_unregister_bh(priv);
459560424e9SKalle Valo 
460560424e9SKalle Valo 	cw1200_debug_release(priv);
461560424e9SKalle Valo 
462560424e9SKalle Valo 	mutex_destroy(&priv->conf_mutex);
463560424e9SKalle Valo 
464560424e9SKalle Valo 	wsm_buf_deinit(&priv->wsm_cmd_buf);
465560424e9SKalle Valo 
466560424e9SKalle Valo 	destroy_workqueue(priv->workqueue);
467560424e9SKalle Valo 	priv->workqueue = NULL;
468560424e9SKalle Valo 
469560424e9SKalle Valo 	if (priv->sdd) {
470560424e9SKalle Valo 		release_firmware(priv->sdd);
471560424e9SKalle Valo 		priv->sdd = NULL;
472560424e9SKalle Valo 	}
473560424e9SKalle Valo 
474560424e9SKalle Valo 	for (i = 0; i < 4; ++i)
475560424e9SKalle Valo 		cw1200_queue_deinit(&priv->tx_queue[i]);
476560424e9SKalle Valo 
477560424e9SKalle Valo 	cw1200_queue_stats_deinit(&priv->tx_queue_stats);
478560424e9SKalle Valo #ifdef CONFIG_PM
479560424e9SKalle Valo 	cw1200_pm_deinit(&priv->pm_state);
480560424e9SKalle Valo #endif
481560424e9SKalle Valo }
482560424e9SKalle Valo 
483560424e9SKalle Valo /* Clock is in KHz */
cw1200_dpll_from_clk(u16 clk_khz)484560424e9SKalle Valo u32 cw1200_dpll_from_clk(u16 clk_khz)
485560424e9SKalle Valo {
486560424e9SKalle Valo 	switch (clk_khz) {
487560424e9SKalle Valo 	case 0x32C8: /* 13000 KHz */
488560424e9SKalle Valo 		return 0x1D89D241;
489560424e9SKalle Valo 	case 0x3E80: /* 16000 KHz */
490560424e9SKalle Valo 		return 0x000001E1;
491560424e9SKalle Valo 	case 0x41A0: /* 16800 KHz */
492560424e9SKalle Valo 		return 0x124931C1;
493560424e9SKalle Valo 	case 0x4B00: /* 19200 KHz */
494560424e9SKalle Valo 		return 0x00000191;
495560424e9SKalle Valo 	case 0x5DC0: /* 24000 KHz */
496560424e9SKalle Valo 		return 0x00000141;
497560424e9SKalle Valo 	case 0x6590: /* 26000 KHz */
498560424e9SKalle Valo 		return 0x0EC4F121;
499560424e9SKalle Valo 	case 0x8340: /* 33600 KHz */
500560424e9SKalle Valo 		return 0x092490E1;
501560424e9SKalle Valo 	case 0x9600: /* 38400 KHz */
502560424e9SKalle Valo 		return 0x100010C1;
503560424e9SKalle Valo 	case 0x9C40: /* 40000 KHz */
504560424e9SKalle Valo 		return 0x000000C1;
505560424e9SKalle Valo 	case 0xBB80: /* 48000 KHz */
506560424e9SKalle Valo 		return 0x000000A1;
507560424e9SKalle Valo 	case 0xCB20: /* 52000 KHz */
508560424e9SKalle Valo 		return 0x07627091;
509560424e9SKalle Valo 	default:
510560424e9SKalle Valo 		pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n",
511560424e9SKalle Valo 		       clk_khz);
512560424e9SKalle Valo 		return 0x0EC4F121;
513560424e9SKalle Valo 	}
514560424e9SKalle Valo }
515560424e9SKalle Valo 
cw1200_core_probe(const struct hwbus_ops * hwbus_ops,struct hwbus_priv * hwbus,struct device * pdev,struct cw1200_common ** core,int ref_clk,const u8 * macaddr,const char * sdd_path,bool have_5ghz)516560424e9SKalle Valo int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
517560424e9SKalle Valo 		      struct hwbus_priv *hwbus,
518560424e9SKalle Valo 		      struct device *pdev,
519560424e9SKalle Valo 		      struct cw1200_common **core,
520560424e9SKalle Valo 		      int ref_clk, const u8 *macaddr,
521560424e9SKalle Valo 		      const char *sdd_path, bool have_5ghz)
522560424e9SKalle Valo {
523560424e9SKalle Valo 	int err = -EINVAL;
524560424e9SKalle Valo 	struct ieee80211_hw *dev;
525560424e9SKalle Valo 	struct cw1200_common *priv;
526560424e9SKalle Valo 	struct wsm_operational_mode mode = {
527560424e9SKalle Valo 		.power_mode = cw1200_power_mode,
528560424e9SKalle Valo 		.disable_more_flag_usage = true,
529560424e9SKalle Valo 	};
530560424e9SKalle Valo 
531560424e9SKalle Valo 	dev = cw1200_init_common(macaddr, have_5ghz);
532560424e9SKalle Valo 	if (!dev)
533560424e9SKalle Valo 		goto err;
534560424e9SKalle Valo 
535560424e9SKalle Valo 	priv = dev->priv;
536560424e9SKalle Valo 	priv->hw_refclk = ref_clk;
537560424e9SKalle Valo 	if (cw1200_refclk)
538560424e9SKalle Valo 		priv->hw_refclk = cw1200_refclk;
539560424e9SKalle Valo 
540560424e9SKalle Valo 	priv->sdd_path = (char *)sdd_path;
541560424e9SKalle Valo 	if (cw1200_sdd_path)
542560424e9SKalle Valo 		priv->sdd_path = cw1200_sdd_path;
543560424e9SKalle Valo 
544560424e9SKalle Valo 	priv->hwbus_ops = hwbus_ops;
545560424e9SKalle Valo 	priv->hwbus_priv = hwbus;
546560424e9SKalle Valo 	priv->pdev = pdev;
547560424e9SKalle Valo 	SET_IEEE80211_DEV(priv->hw, pdev);
548560424e9SKalle Valo 
549560424e9SKalle Valo 	/* Pass struct cw1200_common back up */
550560424e9SKalle Valo 	*core = priv;
551560424e9SKalle Valo 
552560424e9SKalle Valo 	err = cw1200_register_bh(priv);
553560424e9SKalle Valo 	if (err)
554560424e9SKalle Valo 		goto err1;
555560424e9SKalle Valo 
556560424e9SKalle Valo 	err = cw1200_load_firmware(priv);
557560424e9SKalle Valo 	if (err)
558560424e9SKalle Valo 		goto err2;
559560424e9SKalle Valo 
560560424e9SKalle Valo 	if (wait_event_interruptible_timeout(priv->wsm_startup_done,
561560424e9SKalle Valo 					     priv->firmware_ready,
562560424e9SKalle Valo 					     3*HZ) <= 0) {
563560424e9SKalle Valo 		/* TODO: Need to find how to reset device
564560424e9SKalle Valo 		   in QUEUE mode properly.
565560424e9SKalle Valo 		*/
566560424e9SKalle Valo 		pr_err("Timeout waiting on device startup\n");
567560424e9SKalle Valo 		err = -ETIMEDOUT;
568560424e9SKalle Valo 		goto err2;
569560424e9SKalle Valo 	}
570560424e9SKalle Valo 
571560424e9SKalle Valo 	/* Set low-power mode. */
572560424e9SKalle Valo 	wsm_set_operational_mode(priv, &mode);
573560424e9SKalle Valo 
574560424e9SKalle Valo 	/* Enable multi-TX confirmation */
575560424e9SKalle Valo 	wsm_use_multi_tx_conf(priv, true);
576560424e9SKalle Valo 
577560424e9SKalle Valo 	err = cw1200_register_common(dev);
578560424e9SKalle Valo 	if (err)
579560424e9SKalle Valo 		goto err2;
580560424e9SKalle Valo 
581560424e9SKalle Valo 	return err;
582560424e9SKalle Valo 
583560424e9SKalle Valo err2:
584560424e9SKalle Valo 	cw1200_unregister_bh(priv);
585560424e9SKalle Valo err1:
586560424e9SKalle Valo 	cw1200_free_common(dev);
587560424e9SKalle Valo err:
588560424e9SKalle Valo 	*core = NULL;
589560424e9SKalle Valo 	return err;
590560424e9SKalle Valo }
591560424e9SKalle Valo EXPORT_SYMBOL_GPL(cw1200_core_probe);
592560424e9SKalle Valo 
cw1200_core_release(struct cw1200_common * self)593560424e9SKalle Valo void cw1200_core_release(struct cw1200_common *self)
594560424e9SKalle Valo {
595560424e9SKalle Valo 	/* Disable device interrupts */
596560424e9SKalle Valo 	self->hwbus_ops->lock(self->hwbus_priv);
597560424e9SKalle Valo 	__cw1200_irq_enable(self, 0);
598560424e9SKalle Valo 	self->hwbus_ops->unlock(self->hwbus_priv);
599560424e9SKalle Valo 
600560424e9SKalle Valo 	/* And then clean up */
601560424e9SKalle Valo 	cw1200_unregister_common(self->hw);
602560424e9SKalle Valo 	cw1200_free_common(self->hw);
603560424e9SKalle Valo 	return;
604560424e9SKalle Valo }
605560424e9SKalle Valo EXPORT_SYMBOL_GPL(cw1200_core_release);
606