cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

main.c (16785B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
      4 *
      5 * Copyright (c) 2010, ST-Ericsson
      6 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
      7 *
      8 * Based on:
      9 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
     10 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
     11 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
     12 *
     13 * Based on:
     14 * - the islsm (softmac prism54) driver, which is:
     15 *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
     16 * - stlc45xx driver
     17 *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/firmware.h>
     22#include <linux/etherdevice.h>
     23#include <linux/vmalloc.h>
     24#include <linux/random.h>
     25#include <linux/sched.h>
     26#include <net/mac80211.h>
     27
     28#include "cw1200.h"
     29#include "txrx.h"
     30#include "hwbus.h"
     31#include "fwio.h"
     32#include "hwio.h"
     33#include "bh.h"
     34#include "sta.h"
     35#include "scan.h"
     36#include "debug.h"
     37#include "pm.h"
     38
     39MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
     40MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code");
     41MODULE_LICENSE("GPL");
     42MODULE_ALIAS("cw1200_core");
     43
     44/* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
     45static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
     46module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444);
     47MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
     48
     49static char *cw1200_sdd_path;
     50module_param(cw1200_sdd_path, charp, 0644);
     51MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file");
     52static int cw1200_refclk;
     53module_param(cw1200_refclk, int, 0644);
     54MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock");
     55
     56int cw1200_power_mode = wsm_power_mode_quiescent;
     57module_param(cw1200_power_mode, int, 0644);
     58MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode.  0 == active, 1 == doze, 2 == quiescent (default)");
     59
     60#define RATETAB_ENT(_rate, _rateid, _flags)		\
     61	{						\
     62		.bitrate	= (_rate),		\
     63		.hw_value	= (_rateid),		\
     64		.flags		= (_flags),		\
     65	}
     66
     67static struct ieee80211_rate cw1200_rates[] = {
     68	RATETAB_ENT(10,  0,   0),
     69	RATETAB_ENT(20,  1,   0),
     70	RATETAB_ENT(55,  2,   0),
     71	RATETAB_ENT(110, 3,   0),
     72	RATETAB_ENT(60,  6,  0),
     73	RATETAB_ENT(90,  7,  0),
     74	RATETAB_ENT(120, 8,  0),
     75	RATETAB_ENT(180, 9,  0),
     76	RATETAB_ENT(240, 10, 0),
     77	RATETAB_ENT(360, 11, 0),
     78	RATETAB_ENT(480, 12, 0),
     79	RATETAB_ENT(540, 13, 0),
     80};
     81
     82static struct ieee80211_rate cw1200_mcs_rates[] = {
     83	RATETAB_ENT(65,  14, IEEE80211_TX_RC_MCS),
     84	RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
     85	RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
     86	RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
     87	RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
     88	RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
     89	RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
     90	RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
     91};
     92
     93#define cw1200_a_rates		(cw1200_rates + 4)
     94#define cw1200_a_rates_size	(ARRAY_SIZE(cw1200_rates) - 4)
     95#define cw1200_g_rates		(cw1200_rates + 0)
     96#define cw1200_g_rates_size	(ARRAY_SIZE(cw1200_rates))
     97#define cw1200_n_rates		(cw1200_mcs_rates)
     98#define cw1200_n_rates_size	(ARRAY_SIZE(cw1200_mcs_rates))
     99
    100
    101#define CHAN2G(_channel, _freq, _flags) {			\
    102	.band			= NL80211_BAND_2GHZ,		\
    103	.center_freq		= (_freq),			\
    104	.hw_value		= (_channel),			\
    105	.flags			= (_flags),			\
    106	.max_antenna_gain	= 0,				\
    107	.max_power		= 30,				\
    108}
    109
    110#define CHAN5G(_channel, _flags) {				\
    111	.band			= NL80211_BAND_5GHZ,		\
    112	.center_freq	= 5000 + (5 * (_channel)),		\
    113	.hw_value		= (_channel),			\
    114	.flags			= (_flags),			\
    115	.max_antenna_gain	= 0,				\
    116	.max_power		= 30,				\
    117}
    118
    119static struct ieee80211_channel cw1200_2ghz_chantable[] = {
    120	CHAN2G(1, 2412, 0),
    121	CHAN2G(2, 2417, 0),
    122	CHAN2G(3, 2422, 0),
    123	CHAN2G(4, 2427, 0),
    124	CHAN2G(5, 2432, 0),
    125	CHAN2G(6, 2437, 0),
    126	CHAN2G(7, 2442, 0),
    127	CHAN2G(8, 2447, 0),
    128	CHAN2G(9, 2452, 0),
    129	CHAN2G(10, 2457, 0),
    130	CHAN2G(11, 2462, 0),
    131	CHAN2G(12, 2467, 0),
    132	CHAN2G(13, 2472, 0),
    133	CHAN2G(14, 2484, 0),
    134};
    135
    136static struct ieee80211_channel cw1200_5ghz_chantable[] = {
    137	CHAN5G(34, 0),		CHAN5G(36, 0),
    138	CHAN5G(38, 0),		CHAN5G(40, 0),
    139	CHAN5G(42, 0),		CHAN5G(44, 0),
    140	CHAN5G(46, 0),		CHAN5G(48, 0),
    141	CHAN5G(52, 0),		CHAN5G(56, 0),
    142	CHAN5G(60, 0),		CHAN5G(64, 0),
    143	CHAN5G(100, 0),		CHAN5G(104, 0),
    144	CHAN5G(108, 0),		CHAN5G(112, 0),
    145	CHAN5G(116, 0),		CHAN5G(120, 0),
    146	CHAN5G(124, 0),		CHAN5G(128, 0),
    147	CHAN5G(132, 0),		CHAN5G(136, 0),
    148	CHAN5G(140, 0),		CHAN5G(149, 0),
    149	CHAN5G(153, 0),		CHAN5G(157, 0),
    150	CHAN5G(161, 0),		CHAN5G(165, 0),
    151	CHAN5G(184, 0),		CHAN5G(188, 0),
    152	CHAN5G(192, 0),		CHAN5G(196, 0),
    153	CHAN5G(200, 0),		CHAN5G(204, 0),
    154	CHAN5G(208, 0),		CHAN5G(212, 0),
    155	CHAN5G(216, 0),
    156};
    157
    158static struct ieee80211_supported_band cw1200_band_2ghz = {
    159	.channels = cw1200_2ghz_chantable,
    160	.n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
    161	.bitrates = cw1200_g_rates,
    162	.n_bitrates = cw1200_g_rates_size,
    163	.ht_cap = {
    164		.cap = IEEE80211_HT_CAP_GRN_FLD |
    165			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
    166			IEEE80211_HT_CAP_MAX_AMSDU,
    167		.ht_supported = 1,
    168		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
    169		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
    170		.mcs = {
    171			.rx_mask[0] = 0xFF,
    172			.rx_highest = __cpu_to_le16(0x41),
    173			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
    174		},
    175	},
    176};
    177
    178static struct ieee80211_supported_band cw1200_band_5ghz = {
    179	.channels = cw1200_5ghz_chantable,
    180	.n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
    181	.bitrates = cw1200_a_rates,
    182	.n_bitrates = cw1200_a_rates_size,
    183	.ht_cap = {
    184		.cap = IEEE80211_HT_CAP_GRN_FLD |
    185			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
    186			IEEE80211_HT_CAP_MAX_AMSDU,
    187		.ht_supported = 1,
    188		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
    189		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
    190		.mcs = {
    191			.rx_mask[0] = 0xFF,
    192			.rx_highest = __cpu_to_le16(0x41),
    193			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
    194		},
    195	},
    196};
    197
    198static const unsigned long cw1200_ttl[] = {
    199	1 * HZ,	/* VO */
    200	2 * HZ,	/* VI */
    201	5 * HZ, /* BE */
    202	10 * HZ	/* BK */
    203};
    204
    205static const struct ieee80211_ops cw1200_ops = {
    206	.start			= cw1200_start,
    207	.stop			= cw1200_stop,
    208	.add_interface		= cw1200_add_interface,
    209	.remove_interface	= cw1200_remove_interface,
    210	.change_interface	= cw1200_change_interface,
    211	.tx			= cw1200_tx,
    212	.hw_scan		= cw1200_hw_scan,
    213	.set_tim		= cw1200_set_tim,
    214	.sta_notify		= cw1200_sta_notify,
    215	.sta_add		= cw1200_sta_add,
    216	.sta_remove		= cw1200_sta_remove,
    217	.set_key		= cw1200_set_key,
    218	.set_rts_threshold	= cw1200_set_rts_threshold,
    219	.config			= cw1200_config,
    220	.bss_info_changed	= cw1200_bss_info_changed,
    221	.prepare_multicast	= cw1200_prepare_multicast,
    222	.configure_filter	= cw1200_configure_filter,
    223	.conf_tx		= cw1200_conf_tx,
    224	.get_stats		= cw1200_get_stats,
    225	.ampdu_action		= cw1200_ampdu_action,
    226	.flush			= cw1200_flush,
    227#ifdef CONFIG_PM
    228	.suspend		= cw1200_wow_suspend,
    229	.resume			= cw1200_wow_resume,
    230#endif
    231	/* Intentionally not offloaded:					*/
    232	/*.channel_switch	= cw1200_channel_switch,		*/
    233	/*.remain_on_channel	= cw1200_remain_on_channel,		*/
    234	/*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel,	*/
    235};
    236
    237static int cw1200_ba_rx_tids = -1;
    238static int cw1200_ba_tx_tids = -1;
    239module_param(cw1200_ba_rx_tids, int, 0644);
    240module_param(cw1200_ba_tx_tids, int, 0644);
    241MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
    242MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
    243
    244#ifdef CONFIG_PM
    245static const struct wiphy_wowlan_support cw1200_wowlan_support = {
    246	/* Support only for limited wowlan functionalities */
    247	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
    248};
    249#endif
    250
    251
    252static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
    253						const bool have_5ghz)
    254{
    255	int i, band;
    256	struct ieee80211_hw *hw;
    257	struct cw1200_common *priv;
    258
    259	hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
    260	if (!hw)
    261		return NULL;
    262
    263	priv = hw->priv;
    264	priv->hw = hw;
    265	priv->hw_type = -1;
    266	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
    267	priv->rates = cw1200_rates; /* TODO: fetch from FW */
    268	priv->mcs_rates = cw1200_n_rates;
    269	if (cw1200_ba_rx_tids != -1)
    270		priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
    271	else
    272		priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
    273	if (cw1200_ba_tx_tids != -1)
    274		priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
    275	else
    276		priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
    277
    278	ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
    279	ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
    280	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
    281	ieee80211_hw_set(hw, CONNECTION_MONITOR);
    282	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
    283	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
    284	ieee80211_hw_set(hw, SIGNAL_DBM);
    285	ieee80211_hw_set(hw, SUPPORTS_PS);
    286
    287	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
    288					  BIT(NL80211_IFTYPE_ADHOC) |
    289					  BIT(NL80211_IFTYPE_AP) |
    290					  BIT(NL80211_IFTYPE_MESH_POINT) |
    291					  BIT(NL80211_IFTYPE_P2P_CLIENT) |
    292					  BIT(NL80211_IFTYPE_P2P_GO);
    293
    294#ifdef CONFIG_PM
    295	hw->wiphy->wowlan = &cw1200_wowlan_support;
    296#endif
    297
    298	hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
    299
    300	hw->queues = 4;
    301
    302	priv->rts_threshold = -1;
    303
    304	hw->max_rates = 8;
    305	hw->max_rate_tries = 15;
    306	hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
    307		8;  /* TKIP IV */
    308
    309	hw->sta_data_size = sizeof(struct cw1200_sta_priv);
    310
    311	hw->wiphy->bands[NL80211_BAND_2GHZ] = &cw1200_band_2ghz;
    312	if (have_5ghz)
    313		hw->wiphy->bands[NL80211_BAND_5GHZ] = &cw1200_band_5ghz;
    314
    315	/* Channel params have to be cleared before registering wiphy again */
    316	for (band = 0; band < NUM_NL80211_BANDS; band++) {
    317		struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
    318		if (!sband)
    319			continue;
    320		for (i = 0; i < sband->n_channels; i++) {
    321			sband->channels[i].flags = 0;
    322			sband->channels[i].max_antenna_gain = 0;
    323			sband->channels[i].max_power = 30;
    324		}
    325	}
    326
    327	hw->wiphy->max_scan_ssids = 2;
    328	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
    329
    330	if (macaddr)
    331		SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
    332	else
    333		SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
    334
    335	/* Fix up mac address if necessary */
    336	if (hw->wiphy->perm_addr[3] == 0 &&
    337	    hw->wiphy->perm_addr[4] == 0 &&
    338	    hw->wiphy->perm_addr[5] == 0) {
    339		get_random_bytes(&hw->wiphy->perm_addr[3], 3);
    340	}
    341
    342	mutex_init(&priv->wsm_cmd_mux);
    343	mutex_init(&priv->conf_mutex);
    344	priv->workqueue = create_singlethread_workqueue("cw1200_wq");
    345	if (!priv->workqueue) {
    346		ieee80211_free_hw(hw);
    347		return NULL;
    348	}
    349
    350	sema_init(&priv->scan.lock, 1);
    351	INIT_WORK(&priv->scan.work, cw1200_scan_work);
    352	INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
    353	INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
    354	INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
    355			  cw1200_clear_recent_scan_work);
    356	INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
    357	INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
    358	INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
    359	INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
    360	INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
    361	spin_lock_init(&priv->event_queue_lock);
    362	INIT_LIST_HEAD(&priv->event_queue);
    363	INIT_WORK(&priv->event_handler, cw1200_event_handler);
    364	INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
    365	INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
    366	spin_lock_init(&priv->bss_loss_lock);
    367	spin_lock_init(&priv->ps_state_lock);
    368	INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
    369	INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
    370	INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
    371	INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
    372	INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
    373	INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
    374	INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
    375	INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
    376	INIT_WORK(&priv->set_beacon_wakeup_period_work,
    377		  cw1200_set_beacon_wakeup_period_work);
    378	timer_setup(&priv->mcast_timeout, cw1200_mcast_timeout, 0);
    379
    380	if (cw1200_queue_stats_init(&priv->tx_queue_stats,
    381				    CW1200_LINK_ID_MAX,
    382				    cw1200_skb_dtor,
    383				    priv)) {
    384		destroy_workqueue(priv->workqueue);
    385		ieee80211_free_hw(hw);
    386		return NULL;
    387	}
    388
    389	for (i = 0; i < 4; ++i) {
    390		if (cw1200_queue_init(&priv->tx_queue[i],
    391				      &priv->tx_queue_stats, i, 16,
    392				      cw1200_ttl[i])) {
    393			for (; i > 0; i--)
    394				cw1200_queue_deinit(&priv->tx_queue[i - 1]);
    395			cw1200_queue_stats_deinit(&priv->tx_queue_stats);
    396			destroy_workqueue(priv->workqueue);
    397			ieee80211_free_hw(hw);
    398			return NULL;
    399		}
    400	}
    401
    402	init_waitqueue_head(&priv->channel_switch_done);
    403	init_waitqueue_head(&priv->wsm_cmd_wq);
    404	init_waitqueue_head(&priv->wsm_startup_done);
    405	init_waitqueue_head(&priv->ps_mode_switch_done);
    406	wsm_buf_init(&priv->wsm_cmd_buf);
    407	spin_lock_init(&priv->wsm_cmd.lock);
    408	priv->wsm_cmd.done = 1;
    409	tx_policy_init(priv);
    410
    411	return hw;
    412}
    413
    414static int cw1200_register_common(struct ieee80211_hw *dev)
    415{
    416	struct cw1200_common *priv = dev->priv;
    417	int err;
    418
    419#ifdef CONFIG_PM
    420	err = cw1200_pm_init(&priv->pm_state, priv);
    421	if (err) {
    422		pr_err("Cannot init PM. (%d).\n",
    423		       err);
    424		return err;
    425	}
    426#endif
    427
    428	err = ieee80211_register_hw(dev);
    429	if (err) {
    430		pr_err("Cannot register device (%d).\n",
    431		       err);
    432#ifdef CONFIG_PM
    433		cw1200_pm_deinit(&priv->pm_state);
    434#endif
    435		return err;
    436	}
    437
    438	cw1200_debug_init(priv);
    439
    440	pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
    441	return 0;
    442}
    443
    444static void cw1200_free_common(struct ieee80211_hw *dev)
    445{
    446	ieee80211_free_hw(dev);
    447}
    448
    449static void cw1200_unregister_common(struct ieee80211_hw *dev)
    450{
    451	struct cw1200_common *priv = dev->priv;
    452	int i;
    453
    454	ieee80211_unregister_hw(dev);
    455
    456	del_timer_sync(&priv->mcast_timeout);
    457	cw1200_unregister_bh(priv);
    458
    459	cw1200_debug_release(priv);
    460
    461	mutex_destroy(&priv->conf_mutex);
    462
    463	wsm_buf_deinit(&priv->wsm_cmd_buf);
    464
    465	destroy_workqueue(priv->workqueue);
    466	priv->workqueue = NULL;
    467
    468	if (priv->sdd) {
    469		release_firmware(priv->sdd);
    470		priv->sdd = NULL;
    471	}
    472
    473	for (i = 0; i < 4; ++i)
    474		cw1200_queue_deinit(&priv->tx_queue[i]);
    475
    476	cw1200_queue_stats_deinit(&priv->tx_queue_stats);
    477#ifdef CONFIG_PM
    478	cw1200_pm_deinit(&priv->pm_state);
    479#endif
    480}
    481
    482/* Clock is in KHz */
    483u32 cw1200_dpll_from_clk(u16 clk_khz)
    484{
    485	switch (clk_khz) {
    486	case 0x32C8: /* 13000 KHz */
    487		return 0x1D89D241;
    488	case 0x3E80: /* 16000 KHz */
    489		return 0x000001E1;
    490	case 0x41A0: /* 16800 KHz */
    491		return 0x124931C1;
    492	case 0x4B00: /* 19200 KHz */
    493		return 0x00000191;
    494	case 0x5DC0: /* 24000 KHz */
    495		return 0x00000141;
    496	case 0x6590: /* 26000 KHz */
    497		return 0x0EC4F121;
    498	case 0x8340: /* 33600 KHz */
    499		return 0x092490E1;
    500	case 0x9600: /* 38400 KHz */
    501		return 0x100010C1;
    502	case 0x9C40: /* 40000 KHz */
    503		return 0x000000C1;
    504	case 0xBB80: /* 48000 KHz */
    505		return 0x000000A1;
    506	case 0xCB20: /* 52000 KHz */
    507		return 0x07627091;
    508	default:
    509		pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n",
    510		       clk_khz);
    511		return 0x0EC4F121;
    512	}
    513}
    514
    515int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
    516		      struct hwbus_priv *hwbus,
    517		      struct device *pdev,
    518		      struct cw1200_common **core,
    519		      int ref_clk, const u8 *macaddr,
    520		      const char *sdd_path, bool have_5ghz)
    521{
    522	int err = -EINVAL;
    523	struct ieee80211_hw *dev;
    524	struct cw1200_common *priv;
    525	struct wsm_operational_mode mode = {
    526		.power_mode = cw1200_power_mode,
    527		.disable_more_flag_usage = true,
    528	};
    529
    530	dev = cw1200_init_common(macaddr, have_5ghz);
    531	if (!dev)
    532		goto err;
    533
    534	priv = dev->priv;
    535	priv->hw_refclk = ref_clk;
    536	if (cw1200_refclk)
    537		priv->hw_refclk = cw1200_refclk;
    538
    539	priv->sdd_path = (char *)sdd_path;
    540	if (cw1200_sdd_path)
    541		priv->sdd_path = cw1200_sdd_path;
    542
    543	priv->hwbus_ops = hwbus_ops;
    544	priv->hwbus_priv = hwbus;
    545	priv->pdev = pdev;
    546	SET_IEEE80211_DEV(priv->hw, pdev);
    547
    548	/* Pass struct cw1200_common back up */
    549	*core = priv;
    550
    551	err = cw1200_register_bh(priv);
    552	if (err)
    553		goto err1;
    554
    555	err = cw1200_load_firmware(priv);
    556	if (err)
    557		goto err2;
    558
    559	if (wait_event_interruptible_timeout(priv->wsm_startup_done,
    560					     priv->firmware_ready,
    561					     3*HZ) <= 0) {
    562		/* TODO: Need to find how to reset device
    563		   in QUEUE mode properly.
    564		*/
    565		pr_err("Timeout waiting on device startup\n");
    566		err = -ETIMEDOUT;
    567		goto err2;
    568	}
    569
    570	/* Set low-power mode. */
    571	wsm_set_operational_mode(priv, &mode);
    572
    573	/* Enable multi-TX confirmation */
    574	wsm_use_multi_tx_conf(priv, true);
    575
    576	err = cw1200_register_common(dev);
    577	if (err)
    578		goto err2;
    579
    580	return err;
    581
    582err2:
    583	cw1200_unregister_bh(priv);
    584err1:
    585	cw1200_free_common(dev);
    586err:
    587	*core = NULL;
    588	return err;
    589}
    590EXPORT_SYMBOL_GPL(cw1200_core_probe);
    591
    592void cw1200_core_release(struct cw1200_common *self)
    593{
    594	/* Disable device interrupts */
    595	self->hwbus_ops->lock(self->hwbus_priv);
    596	__cw1200_irq_enable(self, 0);
    597	self->hwbus_ops->unlock(self->hwbus_priv);
    598
    599	/* And then clean up */
    600	cw1200_unregister_common(self->hw);
    601	cw1200_free_common(self->hw);
    602	return;
    603}
    604EXPORT_SYMBOL_GPL(cw1200_core_release);