Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00236aed authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by John W. Linville
Browse files

wl1271: Add support for connection quality monitoring



This patch will add support for connection quality monitoring by configuring
rssi triggers to the firmware, and enabling the firmware rssi trigger
functionality.

Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e1972818
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -473,6 +473,9 @@ struct wl1271 {
	/* in dBm */
	int power_level;

	int rssi_thold;
	int last_rssi_event;

	struct wl1271_stats stats;
	struct wl1271_debugfs debugfs;

+71 −0
Original line number Diff line number Diff line
@@ -1165,6 +1165,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
	kfree(acx);
	return ret;
}

int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
{
	struct wl1271_acx_keep_alive_config *acx = NULL;
@@ -1194,3 +1195,73 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
	kfree(acx);
	return ret;
}

int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
				s16 thold, u8 hyst)
{
	struct wl1271_acx_rssi_snr_trigger *acx = NULL;
	int ret = 0;

	wl1271_debug(DEBUG_ACX, "acx rssi snr trigger");

	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
	if (!acx) {
		ret = -ENOMEM;
		goto out;
	}

	wl->last_rssi_event = -1;

	acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
	acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
	acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
	if (enable)
		acx->enable = WL1271_ACX_TRIG_ENABLE;
	else
		acx->enable = WL1271_ACX_TRIG_DISABLE;

	acx->index = WL1271_ACX_TRIG_IDX_RSSI;
	acx->dir = WL1271_ACX_TRIG_DIR_BIDIR;
	acx->threshold = cpu_to_le16(thold);
	acx->hysteresis = hyst;

	ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx));
	if (ret < 0) {
		wl1271_warning("acx rssi snr trigger setting failed: %d", ret);
		goto out;
	}

out:
	kfree(acx);
	return ret;
}

int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
{
	struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
	struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
	int ret = 0;

	wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights");

	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
	if (!acx) {
		ret = -ENOMEM;
		goto out;
	}

	acx->rssi_beacon = c->avg_weight_rssi_beacon;
	acx->rssi_data = c->avg_weight_rssi_data;
	acx->snr_beacon = c->avg_weight_snr_beacon;
	acx->snr_data = c->avg_weight_snr_data;

	ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx));
	if (ret < 0) {
		wl1271_warning("acx rssi snr trigger weights failed: %d", ret);
		goto out;
	}

out:
	kfree(acx);
	return ret;
}
+55 −1
Original line number Diff line number Diff line
@@ -942,6 +942,57 @@ struct wl1271_acx_keep_alive_config {
	u8 padding;
} __attribute__ ((packed));

enum {
	WL1271_ACX_TRIG_TYPE_LEVEL = 0,
	WL1271_ACX_TRIG_TYPE_EDGE,
};

enum {
	WL1271_ACX_TRIG_DIR_LOW = 0,
	WL1271_ACX_TRIG_DIR_HIGH,
	WL1271_ACX_TRIG_DIR_BIDIR,
};

enum {
	WL1271_ACX_TRIG_ENABLE = 1,
	WL1271_ACX_TRIG_DISABLE,
};

enum {
	WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0,
	WL1271_ACX_TRIG_METRIC_RSSI_DATA,
	WL1271_ACX_TRIG_METRIC_SNR_BEACON,
	WL1271_ACX_TRIG_METRIC_SNR_DATA,
};

enum {
	WL1271_ACX_TRIG_IDX_RSSI = 0,
	WL1271_ACX_TRIG_COUNT = 8,
};

struct wl1271_acx_rssi_snr_trigger {
	struct acx_header header;

	__le16 threshold;
	__le16 pacing; /* 0 - 60000 ms */
	u8 metric;
	u8 type;
	u8 dir;
	u8 hysteresis;
	u8 index;
	u8 enable;
	u8 padding[2];
};

struct wl1271_acx_rssi_snr_avg_weights {
	struct acx_header header;

	u8 rssi_beacon;
	u8 rssi_data;
	u8 snr_beacon;
	u8 snr_data;
};

enum {
	ACX_WAKE_UP_CONDITIONS      = 0x0002,
	ACX_MEM_CFG                 = 0x0003,
@@ -990,7 +1041,7 @@ enum {
	ACX_FRAG_CFG                = 0x004F,
	ACX_BET_ENABLE              = 0x0050,
	ACX_RSSI_SNR_TRIGGER        = 0x0051,
	ACX_RSSI_SNR_WEIGHTS        = 0x0051,
	ACX_RSSI_SNR_WEIGHTS        = 0x0052,
	ACX_KEEP_ALIVE_MODE         = 0x0053,
	ACX_SET_KEEP_ALIVE_CONFIG   = 0x0054,
	ACX_BA_SESSION_RESPONDER_POLICY = 0x0055,
@@ -1060,5 +1111,8 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
int wl1271_acx_pm_config(struct wl1271 *wl);
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
				s16 thold, u8 hyst);
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);

#endif /* __WL1271_ACX_H__ */
+2 −1
Original line number Diff line number Diff line
@@ -412,7 +412,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
		SCAN_COMPLETE_EVENT_ID |
		PS_REPORT_EVENT_ID |
		JOIN_EVENT_COMPLETE_ID |
		DISCONNECT_EVENT_COMPLETE_ID;
		DISCONNECT_EVENT_COMPLETE_ID |
		RSSI_SNR_TRIGGER_0_EVENT_ID;

	ret = wl1271_event_unmask(wl);
	if (ret < 0) {
+38 −65
Original line number Diff line number Diff line
@@ -756,65 +756,6 @@ enum {
	CONF_TRIG_EVENT_DIR_BIDIR
};


struct conf_sig_trigger {
	/*
	 * The RSSI / SNR threshold value.
	 *
	 * FIXME: what is the range?
	 */
	s16 threshold;

	/*
	 * Minimum delay between two trigger events for this trigger in ms.
	 *
	 * Range: 0 - 60000
	 */
	u16 pacing;

	/*
	 * The measurement data source for this trigger.
	 *
	 * Range: CONF_TRIG_METRIC_*
	 */
	u8 metric;

	/*
	 * The trigger type of this trigger.
	 *
	 * Range: CONF_TRIG_EVENT_TYPE_*
	 */
	u8 type;

	/*
	 * The direction of the trigger.
	 *
	 * Range: CONF_TRIG_EVENT_DIR_*
	 */
	u8 direction;

	/*
	 * Hysteresis range of the trigger around the threshold (in dB)
	 *
	 * Range: u8
	 */
	u8 hysteresis;

	/*
	 * Index of the trigger rule.
	 *
	 * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1
	 */
	u8 index;

	/*
	 * Enable / disable this rule (to use for clearing rules.)
	 *
	 * Range: 1 - Enabled, 2 - Not enabled
	 */
	u8 enable;
};

struct conf_sig_weights {

	/*
@@ -932,12 +873,6 @@ struct conf_conn_settings {
	 */
	u8 ps_poll_threshold;

	/*
	 * Configuration of signal (rssi/snr) triggers.
	 */
	u8 sig_trigger_count;
	struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS];

	/*
	 * Configuration of signal average weights.
	 */
@@ -1045,6 +980,43 @@ struct conf_pm_config_settings {
	bool host_fast_wakeup_support;
};

struct conf_roam_trigger_settings {
	/*
	 * The minimum interval between two trigger events.
	 *
	 * Range: 0 - 60000 ms
	 */
	u16 trigger_pacing;

	/*
	 * The weight for rssi/beacon average calculation
	 *
	 * Range: 0 - 255
	 */
	u8 avg_weight_rssi_beacon;

	/*
	 * The weight for rssi/data frame average calculation
	 *
	 * Range: 0 - 255
	 */
	u8 avg_weight_rssi_data;

	/*
	 * The weight for snr/beacon average calculation
	 *
	 * Range: 0 - 255
	 */
	u8 avg_weight_snr_beacon;

	/*
	 * The weight for snr/data frame average calculation
	 *
	 * Range: 0 - 255
	 */
	u8 avg_weight_snr_data;
};

struct conf_drv_settings {
	struct conf_sg_settings sg;
	struct conf_rx_settings rx;
@@ -1053,6 +1025,7 @@ struct conf_drv_settings {
	struct conf_init_settings init;
	struct conf_itrim_settings itrim;
	struct conf_pm_config_settings pm_config;
	struct conf_roam_trigger_settings roam_trigger;
};

#endif
Loading