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

Commit e9348cdd authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville
Browse files

ar9170: ar9170: mac80211 interaction code



This patch contains almost all mac80211 interaction code of AR9170.

Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 23b53f4f
Loading
Loading
Loading
Loading
+209 −0
Original line number Diff line number Diff line
/*
 * Atheros AR9170 driver
 *
 * Driver specific definitions
 *
 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, see
 * http://www.gnu.org/licenses/.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
 *
 *    Permission to use, copy, modify, and/or distribute this software for any
 *    purpose with or without fee is hereby granted, provided that the above
 *    copyright notice and this permission notice appear in all copies.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#ifndef __AR9170_H
#define __AR9170_H

#include <linux/completion.h>
#include <linux/spinlock.h>
#include <net/wireless.h>
#include <net/mac80211.h>
#ifdef CONFIG_AR9170_LEDS
#include <linux/leds.h>
#endif /* CONFIG_AR9170_LEDS */
#include "eeprom.h"
#include "hw.h"

#define PAYLOAD_MAX	(AR9170_MAX_CMD_LEN/4 - 1)

enum ar9170_bw {
	AR9170_BW_20,
	AR9170_BW_40_BELOW,
	AR9170_BW_40_ABOVE,

	__AR9170_NUM_BW,
};

enum ar9170_rf_init_mode {
	AR9170_RFI_NONE,
	AR9170_RFI_WARM,
	AR9170_RFI_COLD,
};

#define AR9170_MAX_RX_BUFFER_SIZE		8192

#ifdef CONFIG_AR9170_LEDS
struct ar9170;

struct ar9170_led {
	struct ar9170 *ar;
	struct led_classdev l;
	char name[32];
	unsigned int toggled;
	bool registered;
};

#endif /* CONFIG_AR9170_LEDS */

enum ar9170_device_state {
	AR9170_UNKNOWN_STATE,
	AR9170_STOPPED,
	AR9170_IDLE,
	AR9170_STARTED,
	AR9170_ASSOCIATED,
};

struct ar9170 {
	struct ieee80211_hw *hw;
	struct mutex mutex;
	enum ar9170_device_state state;

	int (*open)(struct ar9170 *);
	void (*stop)(struct ar9170 *);
	int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int);
	int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 ,
			void *, u32 , void *);
	void (*callback_cmd)(struct ar9170 *, u32 , void *);

	/* interface mode settings */
	struct ieee80211_vif *vif;
	u8 mac_addr[ETH_ALEN];
	u8 bssid[ETH_ALEN];

	/* beaconing */
	struct sk_buff *beacon;
	struct work_struct beacon_work;

	/* cryptographic engine */
	u64 usedkeys;
	bool rx_software_decryption;
	bool disable_offload;

	/* filter settings */
	struct work_struct filter_config_work;
	u64 cur_mc_hash, want_mc_hash;
	u32 cur_filter, want_filter;
	unsigned int filter_changed;
	bool sniffer_enabled;

	/* PHY */
	struct ieee80211_channel *channel;
	int noise[4];

	/* power calibration data */
	u8 power_5G_leg[4];
	u8 power_2G_cck[4];
	u8 power_2G_ofdm[4];
	u8 power_5G_ht20[8];
	u8 power_5G_ht40[8];
	u8 power_2G_ht20[8];
	u8 power_2G_ht40[8];

#ifdef CONFIG_AR9170_LEDS
	struct delayed_work led_work;
	struct ar9170_led leds[AR9170_NUM_LEDS];
#endif /* CONFIG_AR9170_LEDS */

	/* qos queue settings */
	spinlock_t tx_stats_lock;
	struct ieee80211_tx_queue_stats tx_stats[5];
	struct ieee80211_tx_queue_params edcf[5];

	spinlock_t cmdlock;
	__le32 cmdbuf[PAYLOAD_MAX + 1];

	/* MAC statistics */
	struct ieee80211_low_level_stats stats;

	/* EEPROM */
	struct ar9170_eeprom eeprom;

	/* global tx status for unregistered Stations. */
	struct sk_buff_head global_tx_status;
	struct sk_buff_head global_tx_status_waste;
	struct delayed_work tx_status_janitor;
};

struct ar9170_sta_info {
	struct sk_buff_head tx_status;
};

#define IS_STARTED(a)		(a->state >= AR9170_STARTED)
#define IS_ACCEPTING_CMD(a)	(a->state >= AR9170_IDLE)

#define AR9170_FILTER_CHANGED_PROMISC		BIT(0)
#define AR9170_FILTER_CHANGED_MULTICAST		BIT(1)
#define AR9170_FILTER_CHANGED_FRAMEFILTER	BIT(2)

/* exported interface */
void *ar9170_alloc(size_t priv_size);
int ar9170_register(struct ar9170 *ar, struct device *pdev);
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
void ar9170_unregister(struct ar9170 *ar);
void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
			     bool update_statistics, u16 tx_status);

/* MAC */
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
int ar9170_init_mac(struct ar9170 *ar);
int ar9170_set_qos(struct ar9170 *ar);
int ar9170_update_multicast(struct ar9170 *ar);
int ar9170_update_frame_filter(struct ar9170 *ar);
int ar9170_set_operating_mode(struct ar9170 *ar);
int ar9170_set_beacon_timers(struct ar9170 *ar);
int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
int ar9170_update_beacon(struct ar9170 *ar);
void ar9170_new_beacon(struct work_struct *work);
int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype,
		      u8 keyidx, u8 *keydata, int keylen);
int ar9170_disable_key(struct ar9170 *ar, u8 id);

/* LEDs */
#ifdef CONFIG_AR9170_LEDS
int ar9170_register_leds(struct ar9170 *ar);
void ar9170_unregister_leds(struct ar9170 *ar);
#endif /* CONFIG_AR9170_LEDS */
int ar9170_init_leds(struct ar9170 *ar);
int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state);

/* PHY / RF */
int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band);
int ar9170_init_rf(struct ar9170 *ar);
int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
		       enum ar9170_rf_init_mode rfi, enum ar9170_bw bw);

#endif /* __AR9170_H */
+130 −0
Original line number Diff line number Diff line
/*
 * Atheros AR9170 driver
 *
 * Basic HW register/memory/command access functions
 *
 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, see
 * http://www.gnu.org/licenses/.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
 *
 *    Permission to use, copy, modify, and/or distribute this software for any
 *    purpose with or without fee is hereby granted, provided that the above
 *    copyright notice and this permission notice appear in all copies.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "ar9170.h"
#include "cmd.h"

int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len)
{
	int err;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return 0;

	err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL);
	if (err)
		printk(KERN_DEBUG "%s: writing memory failed\n",
		       wiphy_name(ar->hw->wiphy));
	return err;
}

int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
{
	__le32 buf[2] = {
		cpu_to_le32(reg),
		cpu_to_le32(val),
	};
	int err;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return 0;

	err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf),
			   (u8 *) buf, 0, NULL);
	if (err)
		printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n",
		       wiphy_name(ar->hw->wiphy), reg, val);
	return err;
}

static int ar9170_read_mreg(struct ar9170 *ar, int nregs,
			    const u32 *regs, u32 *out)
{
	int i, err;
	__le32 *offs, *res;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return 0;

	/* abuse "out" for the register offsets, must be same length */
	offs = (__le32 *)out;
	for (i = 0; i < nregs; i++)
		offs[i] = cpu_to_le32(regs[i]);

	/* also use the same buffer for the input */
	res = (__le32 *)out;

	err = ar->exec_cmd(ar, AR9170_CMD_RREG,
			   4 * nregs, (u8 *)offs,
			   4 * nregs, (u8 *)res);
	if (err)
		return err;

	/* convert result to cpu endian */
	for (i = 0; i < nregs; i++)
		out[i] = le32_to_cpu(res[i]);

	return 0;
}

int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
{
	return ar9170_read_mreg(ar, 1, &reg, val);
}

int ar9170_echo_test(struct ar9170 *ar, u32 v)
{
	__le32 echobuf = cpu_to_le32(v);
	__le32 echores;
	int err;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return -ENODEV;

	err = ar->exec_cmd(ar, AR9170_CMD_ECHO,
			   4, (u8 *)&echobuf,
			   4, (u8 *)&echores);
	if (err)
		return err;

	if (echobuf != echores)
		return -EINVAL;

	return 0;
}
EXPORT_SYMBOL_GPL(ar9170_echo_test);
+91 −0
Original line number Diff line number Diff line
/*
 * Atheros AR9170 driver
 *
 * Basic HW register/memory/command access functions
 *
 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, see
 * http://www.gnu.org/licenses/.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
 *
 *    Permission to use, copy, modify, and/or distribute this software for any
 *    purpose with or without fee is hereby granted, provided that the above
 *    copyright notice and this permission notice appear in all copies.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#ifndef __CMD_H
#define __CMD_H

#include "ar9170.h"

/* basic HW access */
int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len);
int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val);
int ar9170_echo_test(struct ar9170 *ar, u32 v);

/*
 * Macros to facilitate writing multiple registers in a single
 * write-combining USB command. Note that when the first group
 * fails the whole thing will fail without any others attempted,
 * but you won't know which write in the group failed.
 */
#define ar9170_regwrite_begin(ar)					\
do {									\
	int __nreg = 0, __err = 0;					\
	struct ar9170 *__ar = ar;

#define ar9170_regwrite(r, v) do {					\
	__ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r);			\
	__ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v);			\
	__nreg++;							\
	if ((__nreg >= PAYLOAD_MAX/2)) {				\
		if (IS_ACCEPTING_CMD(__ar))				\
			__err = ar->exec_cmd(__ar, AR9170_CMD_WREG,	\
					     8 * __nreg,		\
					     (u8 *) &__ar->cmdbuf[1],	\
					     0, NULL);			\
		__nreg = 0;						\
		if (__err)						\
			goto __regwrite_out;				\
	}								\
} while (0)

#define ar9170_regwrite_finish()					\
__regwrite_out :							\
	if (__nreg) {							\
		if (IS_ACCEPTING_CMD(__ar))				\
			__err = ar->exec_cmd(__ar, AR9170_CMD_WREG,	\
					     8 * __nreg, 		\
					     (u8 *) &__ar->cmdbuf[1],	\
					     0, NULL);			\
		__nreg = 0;						\
	}

#define ar9170_regwrite_result()					\
	__err;								\
} while (0);

#endif /* __CMD_H */
+171 −0
Original line number Diff line number Diff line
/*
 * Atheros AR9170 driver
 *
 * LED handling
 *
 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, see
 * http://www.gnu.org/licenses/.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
 *
 *    Permission to use, copy, modify, and/or distribute this software for any
 *    purpose with or without fee is hereby granted, provided that the above
 *    copyright notice and this permission notice appear in all copies.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "ar9170.h"
#include "cmd.h"

int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state)
{
	return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state);
}

int ar9170_init_leds(struct ar9170 *ar)
{
	int err;

	/* disable LEDs */
	/* GPIO [0/1 mode: output, 2/3: input] */
	err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
	if (err)
		goto out;

	/* GPIO 0/1 value: off */
	err = ar9170_set_leds_state(ar, 0);

out:
	return err;
}

#ifdef CONFIG_AR9170_LEDS
static void ar9170_update_leds(struct work_struct *work)
{
	struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
	int i, tmp, blink_delay = 1000;
	u32 led_val = 0;
	bool rerun = false;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return ;

	mutex_lock(&ar->mutex);
	for (i = 0; i < AR9170_NUM_LEDS; i++)
		if (ar->leds[i].toggled) {
			led_val |= 1 << i;

			tmp = 70 + 200 / (ar->leds[i].toggled);
			if (tmp < blink_delay)
				blink_delay = tmp;

			if (ar->leds[i].toggled > 1)
				ar->leds[i].toggled = 0;

			rerun = true;
		}

	ar9170_set_leds_state(ar, led_val);
	mutex_unlock(&ar->mutex);

	if (rerun)
		queue_delayed_work(ar->hw->workqueue, &ar->led_work,
				   msecs_to_jiffies(blink_delay));
}

static void ar9170_led_brightness_set(struct led_classdev *led,
				      enum led_brightness brightness)
{
	struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
	struct ar9170 *ar = arl->ar;

	arl->toggled++;

	if (likely(IS_ACCEPTING_CMD(ar) && brightness))
		queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
}

static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
			       char *trigger)
{
	int err;

	snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
		 "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name);

	ar->leds[i].ar = ar;
	ar->leds[i].l.name = ar->leds[i].name;
	ar->leds[i].l.brightness_set = ar9170_led_brightness_set;
	ar->leds[i].l.brightness = 0;
	ar->leds[i].l.default_trigger = trigger;

	err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
				    &ar->leds[i].l);
	if (err)
		printk(KERN_ERR "%s: failed to register %s LED (%d).\n",
		       wiphy_name(ar->hw->wiphy), ar->leds[i].name, err);
	else
		ar->leds[i].registered = true;

	return err;
}

void ar9170_unregister_leds(struct ar9170 *ar)
{
	int i;

	cancel_delayed_work_sync(&ar->led_work);

	for (i = 0; i < AR9170_NUM_LEDS; i++)
		if (ar->leds[i].registered) {
			led_classdev_unregister(&ar->leds[i].l);
			ar->leds[i].registered = false;
		}
}

int ar9170_register_leds(struct ar9170 *ar)
{
	int err;

	INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds);

	err = ar9170_register_led(ar, 0, "tx",
				  ieee80211_get_tx_led_name(ar->hw));
	if (err)
		goto fail;

	err = ar9170_register_led(ar, 1, "assoc",
				 ieee80211_get_assoc_led_name(ar->hw));
	if (err)
		goto fail;

	return 0;

fail:
	ar9170_unregister_leds(ar);
	return err;
}

#endif /* CONFIG_AR9170_LEDS */
+1776 −0

File added.

Preview size limit exceeded, changes collapsed.