diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/main.c')
| -rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 674 | 
1 files changed, 466 insertions, 208 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f8748cedbae..adf9bbcf88f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1,3 +1,4 @@ +  /*   * This file is part of wl1271   * @@ -115,6 +116,9 @@ static struct conf_drv_settings default_conf = {  			[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,  			[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,  			[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, +			/* CTS Diluting params */ +			[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, +			[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,  		},  		.state = CONF_SG_PROTECTIVE,  	}, @@ -217,6 +221,8 @@ static struct conf_drv_settings default_conf = {  	.conn = {  		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,  		.listen_interval             = 1, +		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM, +		.suspend_listen_interval     = 3,  		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,  		.bcn_filt_ie_count           = 2,  		.bcn_filt_ie = { @@ -235,12 +241,13 @@ static struct conf_drv_settings default_conf = {  		.broadcast_timeout           = 20000,  		.rx_broadcast_in_ps          = 1,  		.ps_poll_threshold           = 10, -		.ps_poll_recovery_period     = 700,  		.bet_enable                  = CONF_BET_MODE_ENABLE,  		.bet_max_consecutive         = 50,  		.psm_entry_retries           = 8,  		.psm_exit_retries            = 16,  		.psm_entry_nullfunc_retries  = 3, +		.dynamic_ps_timeout          = 100, +		.forced_ps                   = false,  		.keep_alive_interval         = 55000,  		.max_listen_interval         = 20,  	}, @@ -265,6 +272,7 @@ static struct conf_drv_settings default_conf = {  		.min_dwell_time_passive       = 100000,  		.max_dwell_time_passive       = 100000,  		.num_probe_reqs               = 2, +		.split_scan_timeout           = 50000,  	},  	.sched_scan = {  		/* sched_scan requires dwell times in TU instead of TU/1000 */ @@ -672,8 +680,6 @@ static int wl1271_plt_init(struct wl1271 *wl)  		if (ret < 0)  			return ret;  	} -	if (ret < 0) -		return ret;  	/* Chip-specific initializations */  	ret = wl1271_chip_specific_init(wl); @@ -985,16 +991,70 @@ out:  	return IRQ_HANDLED;  } -static int wl1271_fetch_firmware(struct wl1271 *wl) +struct vif_counter_data { +	u8 counter; + +	struct ieee80211_vif *cur_vif; +	bool cur_vif_running; +}; + +static void wl12xx_vif_count_iter(void *data, u8 *mac, +				  struct ieee80211_vif *vif) +{ +	struct vif_counter_data *counter = data; + +	counter->counter++; +	if (counter->cur_vif == vif) +		counter->cur_vif_running = true; +} + +/* caller must not hold wl->mutex, as it might deadlock */ +static void wl12xx_get_vif_count(struct ieee80211_hw *hw, +			       struct ieee80211_vif *cur_vif, +			       struct vif_counter_data *data) +{ +	memset(data, 0, sizeof(*data)); +	data->cur_vif = cur_vif; + +	ieee80211_iterate_active_interfaces(hw, +					    wl12xx_vif_count_iter, data); +} + +static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)  {  	const struct firmware *fw;  	const char *fw_name; +	enum wl12xx_fw_type fw_type;  	int ret; -	if (wl->chip.id == CHIP_ID_1283_PG20) -		fw_name = WL128X_FW_NAME; -	else -		fw_name	= WL127X_FW_NAME; +	if (plt) { +		fw_type = WL12XX_FW_TYPE_PLT; +		if (wl->chip.id == CHIP_ID_1283_PG20) +			fw_name = WL128X_PLT_FW_NAME; +		else +			fw_name	= WL127X_PLT_FW_NAME; +	} else { +		/* +		 * we can't call wl12xx_get_vif_count() here because +		 * wl->mutex is taken, so use the cached last_vif_count value +		 */ +		if (wl->last_vif_count > 1) { +			fw_type = WL12XX_FW_TYPE_MULTI; +			if (wl->chip.id == CHIP_ID_1283_PG20) +				fw_name = WL128X_FW_NAME_MULTI; +			else +				fw_name = WL127X_FW_NAME_MULTI; +		} else { +			fw_type = WL12XX_FW_TYPE_NORMAL; +			if (wl->chip.id == CHIP_ID_1283_PG20) +				fw_name = WL128X_FW_NAME_SINGLE; +			else +				fw_name = WL127X_FW_NAME_SINGLE; +		} +	} + +	if (wl->fw_type == fw_type) +		return 0;  	wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); @@ -1013,6 +1073,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)  	}  	vfree(wl->fw); +	wl->fw_type = WL12XX_FW_TYPE_NONE;  	wl->fw_len = fw->size;  	wl->fw = vmalloc(wl->fw_len); @@ -1024,7 +1085,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)  	memcpy(wl->fw, fw->data, wl->fw_len);  	ret = 0; - +	wl->fw_type = fw_type;  out:  	release_firmware(fw); @@ -1152,7 +1213,7 @@ static void wl1271_recovery_work(struct work_struct *work)  	mutex_lock(&wl->mutex); -	if (wl->state != WL1271_STATE_ON) +	if (wl->state != WL1271_STATE_ON || wl->plt)  		goto out_unlock;  	/* Avoid a recursive recovery */ @@ -1232,10 +1293,9 @@ static int wl1271_setup(struct wl1271 *wl)  	return 0;  } -static int wl1271_chip_wakeup(struct wl1271 *wl) +static int wl12xx_set_power_on(struct wl1271 *wl)  { -	struct wl1271_partition_set partition; -	int ret = 0; +	int ret;  	msleep(WL1271_PRE_POWER_ON_SLEEP);  	ret = wl1271_power_on(wl); @@ -1245,20 +1305,22 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)  	wl1271_io_reset(wl);  	wl1271_io_init(wl); -	/* We don't need a real memory partition here, because we only want -	 * to use the registers at this point. */ -	memset(&partition, 0, sizeof(partition)); -	partition.reg.start = REGISTERS_BASE; -	partition.reg.size = REGISTERS_DOWN_SIZE; -	wl1271_set_partition(wl, &partition); +	wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);  	/* ELP module wake up */  	wl1271_fw_wakeup(wl); -	/* whal_FwCtrl_BootSm() */ +out: +	return ret; +} -	/* 0. read chip id from CHIP_ID */ -	wl->chip.id = wl1271_read32(wl, CHIP_ID_B); +static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) +{ +	int ret = 0; + +	ret = wl12xx_set_power_on(wl); +	if (ret < 0) +		goto out;  	/*  	 * For wl127x based devices we could use the default block @@ -1307,11 +1369,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)  		goto out;  	} -	if (wl->fw == NULL) { -		ret = wl1271_fetch_firmware(wl); -		if (ret < 0) -			goto out; -	} +	ret = wl12xx_fetch_firmware(wl, plt); +	if (ret < 0) +		goto out;  	/* No NVS from netlink, try to get it from the filesystem */  	if (wl->nvs == NULL) { @@ -1343,7 +1403,7 @@ int wl1271_plt_start(struct wl1271 *wl)  	while (retries) {  		retries--; -		ret = wl1271_chip_wakeup(wl); +		ret = wl12xx_chip_wakeup(wl, true);  		if (ret < 0)  			goto power_off; @@ -1355,7 +1415,8 @@ int wl1271_plt_start(struct wl1271 *wl)  		if (ret < 0)  			goto irq_disable; -		wl->state = WL1271_STATE_PLT; +		wl->plt = true; +		wl->state = WL1271_STATE_ON;  		wl1271_notice("firmware booted in PLT mode (%s)",  			      wl->chip.fw_ver_str); @@ -1391,41 +1452,51 @@ out:  	return ret;  } -static int __wl1271_plt_stop(struct wl1271 *wl) +int wl1271_plt_stop(struct wl1271 *wl)  {  	int ret = 0;  	wl1271_notice("power down"); -	if (wl->state != WL1271_STATE_PLT) { +	/* +	 * Interrupts must be disabled before setting the state to OFF. +	 * Otherwise, the interrupt handler might be called and exit without +	 * reading the interrupt status. +	 */ +	wl1271_disable_interrupts(wl); +	mutex_lock(&wl->mutex); +	if (!wl->plt) { +		mutex_unlock(&wl->mutex); + +		/* +		 * This will not necessarily enable interrupts as interrupts +		 * may have been disabled when op_stop was called. It will, +		 * however, balance the above call to disable_interrupts(). +		 */ +		wl1271_enable_interrupts(wl); +  		wl1271_error("cannot power down because not in PLT "  			     "state: %d", wl->state);  		ret = -EBUSY;  		goto out;  	} -	wl1271_power_off(wl); - -	wl->state = WL1271_STATE_OFF; -	wl->rx_counter = 0; -  	mutex_unlock(&wl->mutex); -	wl1271_disable_interrupts(wl); +  	wl1271_flush_deferred_work(wl);  	cancel_work_sync(&wl->netstack_work);  	cancel_work_sync(&wl->recovery_work); -	mutex_lock(&wl->mutex); -out: -	return ret; -} - -int wl1271_plt_stop(struct wl1271 *wl) -{ -	int ret; +	cancel_delayed_work_sync(&wl->elp_work);  	mutex_lock(&wl->mutex); -	ret = __wl1271_plt_stop(wl); +	wl1271_power_off(wl); +	wl->flags = 0; +	wl->state = WL1271_STATE_OFF; +	wl->plt = false; +	wl->rx_counter = 0;  	mutex_unlock(&wl->mutex); + +out:  	return ret;  } @@ -1574,38 +1645,16 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,  	if (ret < 0)  		goto out_unlock; -	/* enter psm if needed*/ -	if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { -		DECLARE_COMPLETION_ONSTACK(compl); +	ret = wl1271_acx_wake_up_conditions(wl, wlvif, +				    wl->conf.conn.suspend_wake_up_event, +				    wl->conf.conn.suspend_listen_interval); -		wlvif->ps_compl = &compl; -		ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE, -				   wlvif->basic_rate, true); -		if (ret < 0) -			goto out_sleep; - -		/* we must unlock here so we will be able to get events */ -		wl1271_ps_elp_sleep(wl); -		mutex_unlock(&wl->mutex); - -		ret = wait_for_completion_timeout( -			&compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); +	if (ret < 0) +		wl1271_error("suspend: set wake up conditions failed: %d", ret); -		mutex_lock(&wl->mutex); -		if (ret <= 0) { -			wl1271_warning("couldn't enter ps mode!"); -			ret = -EBUSY; -			goto out_cleanup; -		} -		ret = wl1271_ps_elp_wakeup(wl); -		if (ret < 0) -			goto out_cleanup; -	} -out_sleep:  	wl1271_ps_elp_sleep(wl); -out_cleanup: -	wlvif->ps_compl = NULL; +  out_unlock:  	mutex_unlock(&wl->mutex);  	return ret; @@ -1648,11 +1697,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl,  static void wl1271_configure_resume(struct wl1271 *wl,  				    struct wl12xx_vif *wlvif)  { -	int ret; -	bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; +	int ret = 0;  	bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; +	bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; -	if (!is_sta && !is_ap) +	if ((!is_ap) && (!is_sta))  		return;  	mutex_lock(&wl->mutex); @@ -1661,12 +1710,16 @@ static void wl1271_configure_resume(struct wl1271 *wl,  		goto out;  	if (is_sta) { -		/* exit psm if it wasn't configured */ -		if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) -			wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE, -					   wlvif->basic_rate, true); +		ret = wl1271_acx_wake_up_conditions(wl, wlvif, +				    wl->conf.conn.wake_up_event, +				    wl->conf.conn.listen_interval); + +		if (ret < 0) +			wl1271_error("resume: wake up conditions failed: %d", +				     ret); +  	} else if (is_ap) { -		wl1271_acx_beacon_filter_opt(wl, wlvif, false); +		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);  	}  	wl1271_ps_elp_sleep(wl); @@ -1709,9 +1762,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,  	wl1271_enable_interrupts(wl);  	flush_work(&wl->tx_work); -	wl12xx_for_each_wlvif(wl, wlvif) { -		flush_delayed_work(&wlvif->pspoll_work); -	}  	flush_delayed_work(&wl->elp_work);  	return 0; @@ -1778,11 +1828,25 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)  	wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); +	/* +	 * Interrupts must be disabled before setting the state to OFF. +	 * Otherwise, the interrupt handler might be called and exit without +	 * reading the interrupt status. +	 */ +	wl1271_disable_interrupts(wl);  	mutex_lock(&wl->mutex);  	if (wl->state == WL1271_STATE_OFF) {  		mutex_unlock(&wl->mutex); + +		/* +		 * This will not necessarily enable interrupts as interrupts +		 * may have been disabled when op_stop was called. It will, +		 * however, balance the above call to disable_interrupts(). +		 */ +		wl1271_enable_interrupts(wl);  		return;  	} +  	/*  	 * this must be before the cancel_work calls below, so that the work  	 * functions don't perform further work. @@ -1794,7 +1858,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)  	list_del(&wl->list);  	mutex_unlock(&wl_list_mutex); -	wl1271_disable_interrupts(wl);  	wl1271_flush_deferred_work(wl);  	cancel_delayed_work_sync(&wl->scan_complete_work);  	cancel_work_sync(&wl->netstack_work); @@ -1969,7 +2032,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)  		  wl1271_rx_streaming_enable_work);  	INIT_WORK(&wlvif->rx_streaming_disable_work,  		  wl1271_rx_streaming_disable_work); -	INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);  	INIT_LIST_HEAD(&wlvif->list);  	setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, @@ -1986,7 +2048,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)  	while (retries) {  		retries--; -		ret = wl1271_chip_wakeup(wl); +		ret = wl12xx_chip_wakeup(wl, false);  		if (ret < 0)  			goto power_off; @@ -2051,11 +2113,60 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)  	return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;  } +/* + * Check whether a fw switch (i.e. moving from one loaded + * fw to another) is needed. This function is also responsible + * for updating wl->last_vif_count, so it must be called before + * loading a non-plt fw (so the correct fw (single-role/multi-role) + * will be used). + */ +static bool wl12xx_need_fw_change(struct wl1271 *wl, +				  struct vif_counter_data vif_counter_data, +				  bool add) +{ +	enum wl12xx_fw_type current_fw = wl->fw_type; +	u8 vif_count = vif_counter_data.counter; + +	if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags)) +		return false; + +	/* increase the vif count if this is a new vif */ +	if (add && !vif_counter_data.cur_vif_running) +		vif_count++; + +	wl->last_vif_count = vif_count; + +	/* no need for fw change if the device is OFF */ +	if (wl->state == WL1271_STATE_OFF) +		return false; + +	if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL) +		return true; +	if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI) +		return true; + +	return false; +} + +/* + * Enter "forced psm". Make sure the sta is in psm against the ap, + * to make the fw switch a bit more disconnection-persistent. + */ +static void wl12xx_force_active_psm(struct wl1271 *wl) +{ +	struct wl12xx_vif *wlvif; + +	wl12xx_for_each_wlvif_sta(wl, wlvif) { +		wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE); +	} +} +  static int wl1271_op_add_interface(struct ieee80211_hw *hw,  				   struct ieee80211_vif *vif)  {  	struct wl1271 *wl = hw->priv;  	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); +	struct vif_counter_data vif_count;  	int ret = 0;  	u8 role_type;  	bool booted = false; @@ -2066,18 +2177,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",  		     ieee80211_vif_type_p2p(vif), vif->addr); +	wl12xx_get_vif_count(hw, vif, &vif_count); +  	mutex_lock(&wl->mutex);  	ret = wl1271_ps_elp_wakeup(wl);  	if (ret < 0)  		goto out_unlock; -	if (wl->vif) { -		wl1271_debug(DEBUG_MAC80211, -			     "multiple vifs are not supported yet"); -		ret = -EBUSY; -		goto out; -	} -  	/*  	 * in some very corner case HW recovery scenarios its possible to  	 * get here before __wl1271_op_remove_interface is complete, so @@ -2089,6 +2195,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  		goto out;  	} +  	ret = wl12xx_init_vif_data(wl, vif);  	if (ret < 0)  		goto out; @@ -2100,6 +2207,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  		goto out;  	} +	if (wl12xx_need_fw_change(wl, vif_count, true)) { +		wl12xx_force_active_psm(wl); +		mutex_unlock(&wl->mutex); +		wl1271_recovery_work(&wl->recovery_work); +		return 0; +	} +  	/*  	 * TODO: after the nvs issue will be solved, move this block  	 * to start(), and make sure here the driver is ON. @@ -2109,7 +2223,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  		 * we still need this in order to configure the fw  		 * while uploading the nvs  		 */ -		memcpy(wl->mac_addr, vif->addr, ETH_ALEN); +		memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);  		booted = wl12xx_init_fw(wl);  		if (!booted) { @@ -2142,7 +2256,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  	if (ret < 0)  		goto out; -	wl->vif = vif;  	list_add(&wlvif->list, &wl->wlvif_list);  	set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); @@ -2175,18 +2288,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,  	if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))  		return; -	wl->vif = NULL; -  	/* because of hardware recovery, we may get here twice */  	if (wl->state != WL1271_STATE_ON)  		return;  	wl1271_info("down"); -	/* enable dyn ps just in case (if left on due to fw crash etc) */ -	if (wlvif->bss_type == BSS_TYPE_STA_BSS) -		ieee80211_enable_dyn_ps(vif); -  	if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&  	    wl->scan_vif == vif) {  		wl->scan.state = WL1271_SCAN_STATE_IDLE; @@ -2253,10 +2360,10 @@ deinit:  		wl->sta_count--;  	mutex_unlock(&wl->mutex); +  	del_timer_sync(&wlvif->rx_streaming_timer);  	cancel_work_sync(&wlvif->rx_streaming_enable_work);  	cancel_work_sync(&wlvif->rx_streaming_disable_work); -	cancel_delayed_work_sync(&wlvif->pspoll_work);  	mutex_lock(&wl->mutex);  } @@ -2267,7 +2374,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,  	struct wl1271 *wl = hw->priv;  	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);  	struct wl12xx_vif *iter; +	struct vif_counter_data vif_count; +	bool cancel_recovery = true; +	wl12xx_get_vif_count(hw, vif, &vif_count);  	mutex_lock(&wl->mutex);  	if (wl->state == WL1271_STATE_OFF || @@ -2286,20 +2396,33 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,  		break;  	}  	WARN_ON(iter != wlvif); +	if (wl12xx_need_fw_change(wl, vif_count, false)) { +		wl12xx_force_active_psm(wl); +		wl12xx_queue_recovery_work(wl); +		cancel_recovery = false; +	}  out:  	mutex_unlock(&wl->mutex); -	cancel_work_sync(&wl->recovery_work); +	if (cancel_recovery) +		cancel_work_sync(&wl->recovery_work);  }  static int wl12xx_op_change_interface(struct ieee80211_hw *hw,  				      struct ieee80211_vif *vif,  				      enum nl80211_iftype new_type, bool p2p)  { +	struct wl1271 *wl = hw->priv; +	int ret; + +	set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);  	wl1271_op_remove_interface(hw, vif);  	vif->type = ieee80211_iftype_p2p(new_type, p2p);  	vif->p2p = p2p; -	return wl1271_op_add_interface(hw, vif); +	ret = wl1271_op_add_interface(hw, vif); + +	clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); +	return ret;  }  static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -2320,6 +2443,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))  		wl1271_info("JOIN while associated."); +	/* clear encryption type */ +	wlvif->encryption_type = KEY_NONE; +  	if (set_assoc)  		set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); @@ -2503,38 +2629,41 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		}  	} -	/* -	 * if mac80211 changes the PSM mode, make sure the mode is not -	 * incorrectly changed after the pspoll failure active window. -	 */ -	if (changed & IEEE80211_CONF_CHANGE_PS) -		clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags); +	if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { -	if (conf->flags & IEEE80211_CONF_PS && -	    !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { -		set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); +		if ((conf->flags & IEEE80211_CONF_PS) && +		    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && +		    !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { -		/* -		 * We enter PSM only if we're already associated. -		 * If we're not, we'll enter it when joining an SSID, -		 * through the bss_info_changed() hook. -		 */ -		if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { -			wl1271_debug(DEBUG_PSM, "psm enabled"); -			ret = wl1271_ps_set_mode(wl, wlvif, -						 STATION_POWER_SAVE_MODE, -						 wlvif->basic_rate, true); -		} -	} else if (!(conf->flags & IEEE80211_CONF_PS) && -		   test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { -		wl1271_debug(DEBUG_PSM, "psm disabled"); +			int ps_mode; +			char *ps_mode_str; -		clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); +			if (wl->conf.conn.forced_ps) { +				ps_mode = STATION_POWER_SAVE_MODE; +				ps_mode_str = "forced"; +			} else { +				ps_mode = STATION_AUTO_PS_MODE; +				ps_mode_str = "auto"; +			} + +			wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); + +			ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); + +			if (ret < 0) +				wl1271_warning("enter %s ps failed %d", +					       ps_mode_str, ret); + +		} else if (!(conf->flags & IEEE80211_CONF_PS) && +			   test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + +			wl1271_debug(DEBUG_PSM, "auto ps disabled"); -		if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))  			ret = wl1271_ps_set_mode(wl, wlvif, -						 STATION_ACTIVE_MODE, -						 wlvif->basic_rate, true); +						 STATION_ACTIVE_MODE); +			if (ret < 0) +				wl1271_warning("exit auto ps failed %d", ret); +		}  	}  	if (conf->power_level != wlvif->power_level) { @@ -2974,6 +3103,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  			wl1271_error("Could not add or replace key");  			goto out_sleep;  		} + +		/* +		 * reconfiguring arp response if the unicast (or common) +		 * encryption key type was changed +		 */ +		if (wlvif->bss_type == BSS_TYPE_STA_BSS && +		    (sta || key_type == KEY_WEP) && +		    wlvif->encryption_type != key_type) { +			wlvif->encryption_type = key_type; +			ret = wl1271_cmd_build_arp_rsp(wl, wlvif); +			if (ret < 0) { +				wl1271_warning("build arp rsp failed: %d", ret); +				goto out_sleep; +			} +		}  		break;  	case DISABLE_KEY: @@ -3043,10 +3187,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,  		goto out_sleep;  	} -	/* cancel ROC before scanning */ -	if (wl12xx_dev_role_started(wlvif)) -		wl12xx_stop_dev(wl, wlvif); -  	ret = wl1271_scan(hw->priv, vif, ssid, len, req);  out_sleep:  	wl1271_ps_elp_sleep(wl); @@ -3108,6 +3248,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,  	mutex_lock(&wl->mutex); +	if (wl->state == WL1271_STATE_OFF) { +		ret = -EAGAIN; +		goto out; +	} +  	ret = wl1271_ps_elp_wakeup(wl);  	if (ret < 0)  		goto out; @@ -3139,6 +3284,9 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,  	mutex_lock(&wl->mutex); +	if (wl->state == WL1271_STATE_OFF) +		goto out; +  	ret = wl1271_ps_elp_wakeup(wl);  	if (ret < 0)  		goto out; @@ -3266,6 +3414,7 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb,  static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,  					 struct ieee80211_vif *vif)  { +	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);  	struct sk_buff *skb;  	int ret; @@ -3273,7 +3422,7 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,  	if (!skb)  		return -EOPNOTSUPP; -	ret = wl1271_cmd_template_set(wl, +	ret = wl1271_cmd_template_set(wl, wlvif->role_id,  				      CMD_TEMPL_AP_PROBE_RESPONSE,  				      skb->data,  				      skb->len, 0, @@ -3297,7 +3446,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,  	/* no need to change probe response if the SSID is set correctly */  	if (wlvif->ssid_len > 0) -		return wl1271_cmd_template_set(wl, +		return wl1271_cmd_template_set(wl, wlvif->role_id,  					       CMD_TEMPL_AP_PROBE_RESPONSE,  					       probe_rsp_data,  					       probe_rsp_len, 0, @@ -3334,7 +3483,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,  	       ptr, probe_rsp_len - (ptr - probe_rsp_data));  	templ_len += probe_rsp_len - (ptr - probe_rsp_data); -	return wl1271_cmd_template_set(wl, +	return wl1271_cmd_template_set(wl, wlvif->role_id,  				       CMD_TEMPL_AP_PROBE_RESPONSE,  				       probe_rsp_templ,  				       templ_len, 0, @@ -3431,7 +3580,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,  		min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);  		tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :  				  CMD_TEMPL_BEACON; -		ret = wl1271_cmd_template_set(wl, tmpl_id, +		ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,  					      beacon->data,  					      beacon->len, 0,  					      min_rate); @@ -3470,7 +3619,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,  						beacon->len,  						min_rate);  		else -			ret = wl1271_cmd_template_set(wl, +			ret = wl1271_cmd_template_set(wl, wlvif->role_id,  						CMD_TEMPL_PROBE_RESPONSE,  						beacon->data,  						beacon->len, 0, @@ -3634,7 +3783,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,  		wlvif->rssi_thold = bss_conf->cqm_rssi_thold;  	} -	if (changed & BSS_CHANGED_BSSID) +	if (changed & BSS_CHANGED_BSSID && +	    (is_ibss || bss_conf->assoc))  		if (!is_zero_ether_addr(bss_conf->bssid)) {  			ret = wl12xx_cmd_build_null_data(wl, wlvif);  			if (ret < 0) @@ -3673,8 +3823,6 @@ sta_not_found:  			wlvif->aid = bss_conf->aid;  			set_assoc = true; -			wlvif->ps_poll_failures = 0; -  			/*  			 * use basic rates from AP, and determine lowest rate  			 * to use with control frames. @@ -3734,9 +3882,6 @@ sta_not_found:  			dev_kfree_skb(wlvif->probereq);  			wlvif->probereq = NULL; -			/* re-enable dynamic ps - just in case */ -			ieee80211_enable_dyn_ps(vif); -  			/* revert back to minimum rates for the current band */  			wl1271_set_band_rate(wl, wlvif);  			wlvif->basic_rate = @@ -3810,34 +3955,6 @@ sta_not_found:  	if (ret < 0)  		goto out; -	if (changed & BSS_CHANGED_ARP_FILTER) { -		__be32 addr = bss_conf->arp_addr_list[0]; -		WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); - -		if (bss_conf->arp_addr_cnt == 1 && -		    bss_conf->arp_filter_enabled) { -			/* -			 * The template should have been configured only upon -			 * association. however, it seems that the correct ip -			 * isn't being set (when sending), so we have to -			 * reconfigure the template upon every ip change. -			 */ -			ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr); -			if (ret < 0) { -				wl1271_warning("build arp rsp failed: %d", ret); -				goto out; -			} - -			ret = wl1271_acx_arp_ip_filter(wl, wlvif, -				ACX_ARP_FILTER_ARP_FILTERING, -				addr); -		} else -			ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); - -		if (ret < 0) -			goto out; -	} -  	if (do_join) {  		ret = wl1271_join(wl, wlvif, set_assoc);  		if (ret < 0) { @@ -3863,19 +3980,6 @@ sta_not_found:  			if (ret < 0)  				goto out;  		} - -		/* If we want to go in PSM but we're not there yet */ -		if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) && -		    !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { -			enum wl1271_cmd_ps_mode mode; - -			mode = STATION_POWER_SAVE_MODE; -			ret = wl1271_ps_set_mode(wl, wlvif, mode, -						 wlvif->basic_rate, -						 true); -			if (ret < 0) -				goto out; -		}  	}  	/* Handle new association with HT. Do this after join. */ @@ -3917,6 +4021,41 @@ sta_not_found:  		}  	} +	/* Handle arp filtering. Done after join. */ +	if ((changed & BSS_CHANGED_ARP_FILTER) || +	    (!is_ibss && (changed & BSS_CHANGED_QOS))) { +		__be32 addr = bss_conf->arp_addr_list[0]; +		wlvif->sta.qos = bss_conf->qos; +		WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); + +		if (bss_conf->arp_addr_cnt == 1 && +		    bss_conf->arp_filter_enabled) { +			wlvif->ip_addr = addr; +			/* +			 * The template should have been configured only upon +			 * association. however, it seems that the correct ip +			 * isn't being set (when sending), so we have to +			 * reconfigure the template upon every ip change. +			 */ +			ret = wl1271_cmd_build_arp_rsp(wl, wlvif); +			if (ret < 0) { +				wl1271_warning("build arp rsp failed: %d", ret); +				goto out; +			} + +			ret = wl1271_acx_arp_ip_filter(wl, wlvif, +				(ACX_ARP_FILTER_ARP_FILTERING | +				 ACX_ARP_FILTER_AUTO_ARP), +				addr); +		} else { +			wlvif->ip_addr = 0; +			ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); +		} + +		if (ret < 0) +			goto out; +	} +  out:  	return;  } @@ -4012,6 +4151,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,  {  	struct wl1271 *wl = hw->priv; +	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);  	u64 mactime = ULLONG_MAX;  	int ret; @@ -4026,7 +4166,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,  	if (ret < 0)  		goto out; -	ret = wl1271_acx_tsf_info(wl, &mactime); +	ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);  	if (ret < 0)  		goto out_sleep; @@ -4373,7 +4513,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,  	/* TODO: change mac80211 to pass vif as param */  	wl12xx_for_each_wlvif_sta(wl, wlvif) { -		ret = wl12xx_cmd_channel_switch(wl, ch_switch); +		ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);  		if (!ret)  			set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); @@ -4467,6 +4607,7 @@ static struct ieee80211_channel wl1271_channels[] = {  /* mapping to indexes for wl1271_rates */  static const u8 wl1271_rate_to_idx_2ghz[] = {  	/* MCS rates are used only with 11n */ +	7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */  	7,                            /* CONF_HW_RXTX_RATE_MCS7 */  	6,                            /* CONF_HW_RXTX_RATE_MCS6 */  	5,                            /* CONF_HW_RXTX_RATE_MCS5 */ @@ -4588,6 +4729,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {  /* mapping to indexes for wl1271_rates_5ghz */  static const u8 wl1271_rate_to_idx_5ghz[] = {  	/* MCS rates are used only with 11n */ +	7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */  	7,                            /* CONF_HW_RXTX_RATE_MCS7 */  	6,                            /* CONF_HW_RXTX_RATE_MCS6 */  	5,                            /* CONF_HW_RXTX_RATE_MCS5 */ @@ -4828,13 +4970,120 @@ static struct bin_attribute fwlog_attr = {  	.read = wl1271_sysfs_read_fwlog,  }; +static bool wl12xx_mac_in_fuse(struct wl1271 *wl) +{ +	bool supported = false; +	u8 major, minor; + +	if (wl->chip.id == CHIP_ID_1283_PG20) { +		major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); +		minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); + +		/* in wl128x we have the MAC address if the PG is >= (2, 1) */ +		if (major > 2 || (major == 2 && minor >= 1)) +			supported = true; +	} else { +		major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); +		minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); + +		/* in wl127x we have the MAC address if the PG is >= (3, 1) */ +		if (major == 3 && minor >= 1) +			supported = true; +	} + +	wl1271_debug(DEBUG_PROBE, +		     "PG Ver major = %d minor = %d, MAC %s present", +		     major, minor, supported ? "is" : "is not"); + +	return supported; +} + +static void wl12xx_derive_mac_addresses(struct wl1271 *wl, +					u32 oui, u32 nic, int n) +{ +	int i; + +	wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d", +		     oui, nic, n); + +	if (nic + n - 1 > 0xffffff) +		wl1271_warning("NIC part of the MAC address wraps around!"); + +	for (i = 0; i < n; i++) { +		wl->addresses[i].addr[0] = (u8)(oui >> 16); +		wl->addresses[i].addr[1] = (u8)(oui >> 8); +		wl->addresses[i].addr[2] = (u8) oui; +		wl->addresses[i].addr[3] = (u8)(nic >> 16); +		wl->addresses[i].addr[4] = (u8)(nic >> 8); +		wl->addresses[i].addr[5] = (u8) nic; +		nic++; +	} + +	wl->hw->wiphy->n_addresses = n; +	wl->hw->wiphy->addresses = wl->addresses; +} + +static void wl12xx_get_fuse_mac(struct wl1271 *wl) +{ +	u32 mac1, mac2; + +	wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]); + +	mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); +	mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); + +	/* these are the two parts of the BD_ADDR */ +	wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + +		((mac1 & 0xff000000) >> 24); +	wl->fuse_nic_addr = mac1 & 0xffffff; + +	wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); +} + +static int wl12xx_get_hw_info(struct wl1271 *wl) +{ +	int ret; +	u32 die_info; + +	ret = wl12xx_set_power_on(wl); +	if (ret < 0) +		goto out; + +	wl->chip.id = wl1271_read32(wl, CHIP_ID_B); + +	if (wl->chip.id == CHIP_ID_1283_PG20) +		die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); +	else +		die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); + +	wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; + +	if (!wl12xx_mac_in_fuse(wl)) { +		wl->fuse_oui_addr = 0; +		wl->fuse_nic_addr = 0; +	} else { +		wl12xx_get_fuse_mac(wl); +	} + +	wl1271_power_off(wl); +out: +	return ret; +} +  static int wl1271_register_hw(struct wl1271 *wl)  {  	int ret; +	u32 oui_addr = 0, nic_addr = 0;  	if (wl->mac80211_registered)  		return 0; +	ret = wl12xx_get_hw_info(wl); +	if (ret < 0) { +		wl1271_error("couldn't get hw info"); +		goto out; +	} +  	ret = wl1271_fetch_nvs(wl);  	if (ret == 0) {  		/* NOTE: The wl->nvs->nvs element must be first, in @@ -4843,20 +5092,25 @@ static int wl1271_register_hw(struct wl1271 *wl)  		 */  		u8 *nvs_ptr = (u8 *)wl->nvs; -		wl->mac_addr[0] = nvs_ptr[11]; -		wl->mac_addr[1] = nvs_ptr[10]; -		wl->mac_addr[2] = nvs_ptr[6]; -		wl->mac_addr[3] = nvs_ptr[5]; -		wl->mac_addr[4] = nvs_ptr[4]; -		wl->mac_addr[5] = nvs_ptr[3]; +		oui_addr = +			(nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6]; +		nic_addr = +			(nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];  	} -	SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); +	/* if the MAC address is zeroed in the NVS derive from fuse */ +	if (oui_addr == 0 && nic_addr == 0) { +		oui_addr = wl->fuse_oui_addr; +		/* fuse has the BD_ADDR, the WLAN addresses are the next two */ +		nic_addr = wl->fuse_nic_addr + 1; +	} + +	wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);  	ret = ieee80211_register_hw(wl->hw);  	if (ret < 0) {  		wl1271_error("unable to register mac80211 hw: %d", ret); -		return ret; +		goto out;  	}  	wl->mac80211_registered = true; @@ -4867,13 +5121,14 @@ static int wl1271_register_hw(struct wl1271 *wl)  	wl1271_notice("loaded"); -	return 0; +out: +	return ret;  }  static void wl1271_unregister_hw(struct wl1271 *wl)  { -	if (wl->state == WL1271_STATE_PLT) -		__wl1271_plt_stop(wl); +	if (wl->plt) +		wl1271_plt_stop(wl);  	unregister_netdevice_notifier(&wl1271_dev_notifier);  	ieee80211_unregister_hw(wl->hw); @@ -4892,7 +5147,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  	};  	/* The tx descriptor buffer and the TKIP space. */ -	wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + +	wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +  		sizeof(struct wl1271_tx_hw_descr);  	/* unit us */ @@ -4902,6 +5157,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  	wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |  		IEEE80211_HW_SUPPORTS_PS | +		IEEE80211_HW_SUPPORTS_DYNAMIC_PS |  		IEEE80211_HW_SUPPORTS_UAPSD |  		IEEE80211_HW_HAS_RATE_CONTROL |  		IEEE80211_HW_CONNECTION_MONITOR | @@ -4909,7 +5165,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  		IEEE80211_HW_SPECTRUM_MGMT |  		IEEE80211_HW_AP_LINK_PS |  		IEEE80211_HW_AMPDU_AGGREGATION | -		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW; +		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | +		IEEE80211_HW_SCAN_WHILE_IDLE;  	wl->hw->wiphy->cipher_suites = cipher_suites;  	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -4925,10 +5182,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  	 * should be the maximum length possible for a template, without  	 * the IEEE80211 header of the template  	 */ -	wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - +	wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -  			sizeof(struct ieee80211_header); -	wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - +	wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -  		sizeof(struct ieee80211_header);  	wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; @@ -5022,7 +5279,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)  	wl->rx_counter = 0;  	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;  	wl->band = IEEE80211_BAND_2GHZ; -	wl->vif = NULL;  	wl->flags = 0;  	wl->sg_enabled = true;  	wl->hw_pg_ver = -1; @@ -5047,6 +5303,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)  	spin_lock_init(&wl->wl_lock);  	wl->state = WL1271_STATE_OFF; +	wl->fw_type = WL12XX_FW_TYPE_NONE;  	mutex_init(&wl->mutex);  	/* Apply default driver configuration. */ @@ -5114,6 +5371,7 @@ static int wl1271_free_hw(struct wl1271 *wl)  	vfree(wl->fw);  	wl->fw = NULL; +	wl->fw_type = WL12XX_FW_TYPE_NONE;  	kfree(wl->nvs);  	wl->nvs = NULL; @@ -5300,7 +5558,7 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);  MODULE_PARM_DESC(debug_level, "wl12xx debugging level");  module_param_named(fwlog, fwlog_param, charp, 0); -MODULE_PARM_DESC(keymap, +MODULE_PARM_DESC(fwlog,  		 "FW logger options: continuous, ondemand, dbgpins or disable");  module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);  |