forked from freifunk-franken/firmware
backport mac80211/ath9k-patches from owrt trunk r36007 (now really ;) )
This commit is contained in:
parent
f245986bc8
commit
354da25bbd
|
@ -0,0 +1,8 @@
|
|||
--- a/compat/scripts/gen-compat-config.sh
|
||||
+++ b/compat/scripts/gen-compat-config.sh
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/bin/bash
|
||||
+#!/usr/bin/env bash
|
||||
# Copyright 2012 Luis R. Rodriguez <mcgrof@frijolero.org>
|
||||
# Copyright 2012 Hauke Mehrtens <hauke@hauke-m.de>
|
||||
#
|
|
@ -0,0 +1,153 @@
|
|||
--- a/include/linux/compat-2.6.h
|
||||
+++ b/include/linux/compat-2.6.h
|
||||
@@ -69,6 +69,7 @@ void compat_dependency_symbol(void);
|
||||
#include <linux/compat-3.6.h>
|
||||
#include <linux/compat-3.7.h>
|
||||
#include <linux/compat-3.8.h>
|
||||
+#include <linux/compat-3.9.h>
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/linux/compat-3.9.h
|
||||
@@ -0,0 +1,140 @@
|
||||
+#ifndef LINUX_3_9_COMPAT_H
|
||||
+#define LINUX_3_9_COMPAT_H
|
||||
+
|
||||
+#include <linux/version.h>
|
||||
+
|
||||
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
|
||||
+
|
||||
+#include <linux/idr.h>
|
||||
+#include <linux/list.h>
|
||||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25))
|
||||
+#include <linux/rculist.h>
|
||||
+#endif
|
||||
+#include <net/sock.h>
|
||||
+#include <linux/tty.h>
|
||||
+#include <linux/tty_flip.h>
|
||||
+
|
||||
+/* include this before changing hlist_for_each_* to use the old versions. */
|
||||
+#include <net/sch_generic.h>
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * backport of idr idr_alloc() usage
|
||||
+ *
|
||||
+ * This backports a patch series send by Tejun Heo:
|
||||
+ * https://lkml.org/lkml/2013/2/2/159
|
||||
+ */
|
||||
+static inline void compat_idr_destroy(struct idr *idp)
|
||||
+{
|
||||
+ idr_remove_all(idp);
|
||||
+ idr_destroy(idp);
|
||||
+}
|
||||
+#define idr_destroy(idp) compat_idr_destroy(idp)
|
||||
+
|
||||
+static inline int idr_alloc(struct idr *idr, void *ptr, int start, int end,
|
||||
+ gfp_t gfp_mask)
|
||||
+{
|
||||
+ int id, ret;
|
||||
+
|
||||
+ do {
|
||||
+ if (!idr_pre_get(idr, gfp_mask))
|
||||
+ return -ENOMEM;
|
||||
+ ret = idr_get_new_above(idr, ptr, start, &id);
|
||||
+ if (!ret && id > end) {
|
||||
+ idr_remove(idr, id);
|
||||
+ ret = -ENOSPC;
|
||||
+ }
|
||||
+ } while (ret == -EAGAIN);
|
||||
+
|
||||
+ return ret ? ret : id;
|
||||
+}
|
||||
+
|
||||
+static inline void idr_preload(gfp_t gfp_mask)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline void idr_preload_end(void)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * backport:
|
||||
+ *
|
||||
+ * commit 0bbacca7c3911451cea923b0ad6389d58e3d9ce9
|
||||
+ * Author: Sasha Levin <sasha.levin@oracle.com>
|
||||
+ * Date: Thu Feb 7 12:32:18 2013 +1100
|
||||
+ *
|
||||
+ * hlist: drop the node parameter from iterators
|
||||
+ */
|
||||
+
|
||||
+#define hlist_entry_safe(ptr, type, member) \
|
||||
+ (ptr) ? hlist_entry(ptr, type, member) : NULL
|
||||
+
|
||||
+#undef hlist_for_each_entry
|
||||
+/**
|
||||
+ * hlist_for_each_entry - iterate over list of given type
|
||||
+ * @pos: the type * to use as a loop cursor.
|
||||
+ * @head: the head for your list.
|
||||
+ * @member: the name of the hlist_node within the struct.
|
||||
+ */
|
||||
+#define hlist_for_each_entry(pos, head, member) \
|
||||
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \
|
||||
+ pos; \
|
||||
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
|
||||
+
|
||||
+#undef hlist_for_each_entry_safe
|
||||
+/**
|
||||
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
+ * @pos: the type * to use as a loop cursor.
|
||||
+ * @n: another &struct hlist_node to use as temporary storage
|
||||
+ * @head: the head for your list.
|
||||
+ * @member: the name of the hlist_node within the struct.
|
||||
+ */
|
||||
+#define hlist_for_each_entry_safe(pos, n, head, member) \
|
||||
+ for (pos = hlist_entry_safe((head)->first, typeof(*pos), member); \
|
||||
+ pos && ({ n = pos->member.next; 1; }); \
|
||||
+ pos = hlist_entry_safe(n, typeof(*pos), member))
|
||||
+
|
||||
+#undef hlist_for_each_entry_rcu
|
||||
+/**
|
||||
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
|
||||
+ * @pos: the type * to use as a loop cursor.
|
||||
+ * @head: the head for your list.
|
||||
+ * @member: the name of the hlist_node within the struct.
|
||||
+ *
|
||||
+ * This list-traversal primitive may safely run concurrently with
|
||||
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
|
||||
+ * as long as the traversal is guarded by rcu_read_lock().
|
||||
+ */
|
||||
+#define hlist_for_each_entry_rcu(pos, head, member) \
|
||||
+ for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
|
||||
+ typeof(*(pos)), member); \
|
||||
+ pos; \
|
||||
+ pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
|
||||
+ &(pos)->member)), typeof(*(pos)), member))
|
||||
+
|
||||
+#undef sk_for_each
|
||||
+#define sk_for_each(__sk, list) \
|
||||
+ hlist_for_each_entry(__sk, list, sk_node)
|
||||
+
|
||||
+#define tty_flip_buffer_push(port) tty_flip_buffer_push((port)->tty)
|
||||
+#define tty_insert_flip_string(port, chars, size) tty_insert_flip_string((port)->tty, chars, size)
|
||||
+
|
||||
+/**
|
||||
+ * backport of:
|
||||
+ *
|
||||
+ * commit 496ad9aa8ef448058e36ca7a787c61f2e63f0f54
|
||||
+ * Author: Al Viro <viro@zeniv.linux.org.uk>
|
||||
+ * Date: Wed Jan 23 17:07:38 2013 -0500
|
||||
+ *
|
||||
+ * new helper: file_inode(file)
|
||||
+ */
|
||||
+static inline struct inode *file_inode(struct file *f)
|
||||
+{
|
||||
+ return f->f_path.dentry->d_inode;
|
||||
+}
|
||||
+
|
||||
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)) */
|
||||
+
|
||||
+#endif /* LINUX_3_9_COMPAT_H */
|
|
@ -0,0 +1,212 @@
|
|||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -72,9 +72,9 @@ static inline struct mesh_table *resize_
|
||||
* it's used twice. So it is illegal to do
|
||||
* for_each_mesh_entry(rcu_dereference(...), ...)
|
||||
*/
|
||||
-#define for_each_mesh_entry(tbl, p, node, i) \
|
||||
+#define for_each_mesh_entry(tbl, node, i) \
|
||||
for (i = 0; i <= tbl->hash_mask; i++) \
|
||||
- hlist_for_each_entry_rcu(node, p, &tbl->hash_buckets[i], list)
|
||||
+ hlist_for_each_entry_rcu(node, &tbl->hash_buckets[i], list)
|
||||
|
||||
|
||||
static struct mesh_table *mesh_table_alloc(int size_order)
|
||||
@@ -139,7 +139,7 @@ static void mesh_table_free(struct mesh_
|
||||
}
|
||||
if (free_leafs) {
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
- hlist_for_each_entry_safe(gate, p, q,
|
||||
+ hlist_for_each_entry_safe(gate, q,
|
||||
tbl->known_gates, list) {
|
||||
hlist_del(&gate->list);
|
||||
kfree(gate);
|
||||
@@ -333,12 +333,11 @@ static struct mesh_path *mpath_lookup(st
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct mesh_path *mpath;
|
||||
- struct hlist_node *n;
|
||||
struct hlist_head *bucket;
|
||||
struct mpath_node *node;
|
||||
|
||||
bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
|
||||
- hlist_for_each_entry_rcu(node, n, bucket, list) {
|
||||
+ hlist_for_each_entry_rcu(node, bucket, list) {
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata == sdata &&
|
||||
ether_addr_equal(dst, mpath->dst)) {
|
||||
@@ -389,11 +388,10 @@ mesh_path_lookup_by_idx(struct ieee80211
|
||||
{
|
||||
struct mesh_table *tbl = rcu_dereference(mesh_paths);
|
||||
struct mpath_node *node;
|
||||
- struct hlist_node *p;
|
||||
int i;
|
||||
int j = 0;
|
||||
|
||||
- for_each_mesh_entry(tbl, p, node, i) {
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
if (sdata && node->mpath->sdata != sdata)
|
||||
continue;
|
||||
if (j++ == idx) {
|
||||
@@ -417,13 +415,12 @@ int mesh_path_add_gate(struct mesh_path
|
||||
{
|
||||
struct mesh_table *tbl;
|
||||
struct mpath_node *gate, *new_gate;
|
||||
- struct hlist_node *n;
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = rcu_dereference(mesh_paths);
|
||||
|
||||
- hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list)
|
||||
+ hlist_for_each_entry_rcu(gate, tbl->known_gates, list)
|
||||
if (gate->mpath == mpath) {
|
||||
err = -EEXIST;
|
||||
goto err_rcu;
|
||||
@@ -460,9 +457,9 @@ err_rcu:
|
||||
static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
{
|
||||
struct mpath_node *gate;
|
||||
- struct hlist_node *p, *q;
|
||||
+ struct hlist_node *q;
|
||||
|
||||
- hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) {
|
||||
+ hlist_for_each_entry_safe(gate, q, tbl->known_gates, list) {
|
||||
if (gate->mpath != mpath)
|
||||
continue;
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
@@ -504,7 +501,6 @@ int mesh_path_add(struct ieee80211_sub_i
|
||||
struct mesh_path *mpath, *new_mpath;
|
||||
struct mpath_node *node, *new_node;
|
||||
struct hlist_head *bucket;
|
||||
- struct hlist_node *n;
|
||||
int grow = 0;
|
||||
int err = 0;
|
||||
u32 hash_idx;
|
||||
@@ -550,7 +546,7 @@ int mesh_path_add(struct ieee80211_sub_i
|
||||
spin_lock(&tbl->hashwlock[hash_idx]);
|
||||
|
||||
err = -EEXIST;
|
||||
- hlist_for_each_entry(node, n, bucket, list) {
|
||||
+ hlist_for_each_entry(node, bucket, list) {
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata == sdata &&
|
||||
ether_addr_equal(dst, mpath->dst))
|
||||
@@ -640,7 +636,6 @@ int mpp_path_add(struct ieee80211_sub_if
|
||||
struct mesh_path *mpath, *new_mpath;
|
||||
struct mpath_node *node, *new_node;
|
||||
struct hlist_head *bucket;
|
||||
- struct hlist_node *n;
|
||||
int grow = 0;
|
||||
int err = 0;
|
||||
u32 hash_idx;
|
||||
@@ -680,7 +675,7 @@ int mpp_path_add(struct ieee80211_sub_if
|
||||
spin_lock(&tbl->hashwlock[hash_idx]);
|
||||
|
||||
err = -EEXIST;
|
||||
- hlist_for_each_entry(node, n, bucket, list) {
|
||||
+ hlist_for_each_entry(node, bucket, list) {
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata == sdata &&
|
||||
ether_addr_equal(dst, mpath->dst))
|
||||
@@ -725,14 +720,13 @@ void mesh_plink_broken(struct sta_info *
|
||||
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
- struct hlist_node *p;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
int i;
|
||||
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = rcu_dereference(mesh_paths);
|
||||
- for_each_mesh_entry(tbl, p, node, i) {
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
mpath = node->mpath;
|
||||
if (rcu_dereference(mpath->next_hop) == sta &&
|
||||
mpath->flags & MESH_PATH_ACTIVE &&
|
||||
@@ -792,13 +786,12 @@ void mesh_path_flush_by_nexthop(struct s
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
- struct hlist_node *p;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
read_lock_bh(&pathtbl_resize_lock);
|
||||
tbl = resize_dereference_mesh_paths();
|
||||
- for_each_mesh_entry(tbl, p, node, i) {
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
mpath = node->mpath;
|
||||
if (rcu_dereference(mpath->next_hop) == sta) {
|
||||
spin_lock(&tbl->hashwlock[i]);
|
||||
@@ -815,11 +808,9 @@ static void table_flush_by_iface(struct
|
||||
{
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
- struct hlist_node *p;
|
||||
int i;
|
||||
|
||||
- WARN_ON(!rcu_read_lock_held());
|
||||
- for_each_mesh_entry(tbl, p, node, i) {
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata != sdata)
|
||||
continue;
|
||||
@@ -865,7 +856,6 @@ int mesh_path_del(struct ieee80211_sub_i
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
struct hlist_head *bucket;
|
||||
- struct hlist_node *n;
|
||||
int hash_idx;
|
||||
int err = 0;
|
||||
|
||||
@@ -875,7 +865,7 @@ int mesh_path_del(struct ieee80211_sub_i
|
||||
bucket = &tbl->hash_buckets[hash_idx];
|
||||
|
||||
spin_lock(&tbl->hashwlock[hash_idx]);
|
||||
- hlist_for_each_entry(node, n, bucket, list) {
|
||||
+ hlist_for_each_entry(node, bucket, list) {
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata == sdata &&
|
||||
ether_addr_equal(addr, mpath->dst)) {
|
||||
@@ -920,7 +910,6 @@ void mesh_path_tx_pending(struct mesh_pa
|
||||
int mesh_path_send_to_gates(struct mesh_path *mpath)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = mpath->sdata;
|
||||
- struct hlist_node *n;
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *from_mpath = mpath;
|
||||
struct mpath_node *gate = NULL;
|
||||
@@ -935,7 +924,7 @@ int mesh_path_send_to_gates(struct mesh_
|
||||
if (!known_gates)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
- hlist_for_each_entry_rcu(gate, n, known_gates, list) {
|
||||
+ hlist_for_each_entry_rcu(gate, known_gates, list) {
|
||||
if (gate->mpath->sdata != sdata)
|
||||
continue;
|
||||
|
||||
@@ -951,7 +940,7 @@ int mesh_path_send_to_gates(struct mesh_
|
||||
}
|
||||
}
|
||||
|
||||
- hlist_for_each_entry_rcu(gate, n, known_gates, list)
|
||||
+ hlist_for_each_entry_rcu(gate, known_gates, list)
|
||||
if (gate->mpath->sdata == sdata) {
|
||||
mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
|
||||
mesh_path_tx_pending(gate->mpath);
|
||||
@@ -1096,12 +1085,11 @@ void mesh_path_expire(struct ieee80211_s
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
- struct hlist_node *p;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = rcu_dereference(mesh_paths);
|
||||
- for_each_mesh_entry(tbl, p, node, i) {
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
if (node->mpath->sdata != sdata)
|
||||
continue;
|
||||
mpath = node->mpath;
|
|
@ -0,0 +1,67 @@
|
|||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -313,7 +313,7 @@ void ieee80211_restart_hw(struct ieee802
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_restart_hw);
|
||||
|
||||
-#ifdef CONFIG_INET
|
||||
+#ifdef __disabled__CONFIG_INET
|
||||
static int ieee80211_ifa_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
@@ -372,7 +372,7 @@ static int ieee80211_ifa_changed(struct
|
||||
}
|
||||
#endif
|
||||
|
||||
-#if IS_ENABLED(CONFIG_IPV6)
|
||||
+#if IS_ENABLED(__disabled__CONFIG_IPV6)
|
||||
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
@@ -1015,14 +1015,14 @@ int ieee80211_register_hw(struct ieee802
|
||||
goto fail_pm_qos;
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_INET
|
||||
+#ifdef __disabled__CONFIG_INET
|
||||
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
|
||||
result = register_inetaddr_notifier(&local->ifa_notifier);
|
||||
if (result)
|
||||
goto fail_ifa;
|
||||
#endif
|
||||
|
||||
-#if IS_ENABLED(CONFIG_IPV6)
|
||||
+#if IS_ENABLED(__disabled__CONFIG_IPV6)
|
||||
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
|
||||
result = register_inet6addr_notifier(&local->ifa6_notifier);
|
||||
if (result)
|
||||
@@ -1034,13 +1034,13 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
return 0;
|
||||
|
||||
-#if IS_ENABLED(CONFIG_IPV6)
|
||||
+#if IS_ENABLED(__disabled__CONFIG_IPV6)
|
||||
fail_ifa6:
|
||||
-#ifdef CONFIG_INET
|
||||
+#ifdef __disabled__CONFIG_INET
|
||||
unregister_inetaddr_notifier(&local->ifa_notifier);
|
||||
#endif
|
||||
#endif
|
||||
-#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
|
||||
+#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6)
|
||||
fail_ifa:
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
@@ -1073,10 +1073,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
-#ifdef CONFIG_INET
|
||||
+#ifdef __disabled__CONFIG_INET
|
||||
unregister_inetaddr_notifier(&local->ifa_notifier);
|
||||
#endif
|
||||
-#if IS_ENABLED(CONFIG_IPV6)
|
||||
+#if IS_ENABLED(__disabled__CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&local->ifa6_notifier);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "hw.h"
|
||||
@@ -519,8 +520,16 @@ static int ath9k_hw_init_macaddr(struct
|
||||
common->macaddr[2 * i] = eeval >> 8;
|
||||
common->macaddr[2 * i + 1] = eeval & 0xff;
|
||||
}
|
||||
- if (sum == 0 || sum == 0xffff * 3)
|
||||
- return -EADDRNOTAVAIL;
|
||||
+ if (!is_valid_ether_addr(common->macaddr)) {
|
||||
+ ath_err(common,
|
||||
+ "eeprom contains invalid mac address: %pM\n",
|
||||
+ common->macaddr);
|
||||
+
|
||||
+ random_ether_addr(common->macaddr);
|
||||
+ ath_err(common,
|
||||
+ "random mac address will be used: %pM\n",
|
||||
+ common->macaddr);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||||
@@ -89,13 +89,8 @@ ath5k_add_interface(struct ieee80211_hw
|
||||
goto end;
|
||||
}
|
||||
|
||||
- /* Don't allow other interfaces if one ad-hoc is configured.
|
||||
- * TODO: Fix the problems with ad-hoc and multiple other interfaces.
|
||||
- * We would need to operate the HW in ad-hoc mode to allow TSF updates
|
||||
- * for the IBSS, but this breaks with additional AP or STA interfaces
|
||||
- * at the moment. */
|
||||
- if (ah->num_adhoc_vifs ||
|
||||
- (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
|
||||
+ /* Don't allow more than one ad-hoc interface */
|
||||
+ if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");
|
||||
ret = -ELNRNG;
|
||||
goto end;
|
||||
--- a/drivers/net/wireless/ath/ath5k/base.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
||||
@@ -1868,7 +1868,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
|
||||
}
|
||||
|
||||
if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
|
||||
- ah->num_mesh_vifs > 1) ||
|
||||
+ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) ||
|
||||
ah->opmode == NL80211_IFTYPE_MESH_POINT) {
|
||||
u64 tsf = ath5k_hw_get_tsf64(ah);
|
||||
u32 tsftu = TSF_TO_TU(tsf);
|
||||
@@ -1954,7 +1954,7 @@ ath5k_beacon_update_timers(struct ath5k_
|
||||
|
||||
intval = ah->bintval & AR5K_BEACON_PERIOD;
|
||||
if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
|
||||
- + ah->num_mesh_vifs > 1) {
|
||||
+ + ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) {
|
||||
intval /= ATH_BCBUF; /* staggered multi-bss beacons */
|
||||
if (intval < 15)
|
||||
ATH5K_WARN(ah, "intval %u is too low, min 15\n",
|
||||
@@ -2418,6 +2418,7 @@ static const struct ieee80211_iface_limi
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_AP) },
|
||||
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination if_comb = {
|
|
@ -0,0 +1,56 @@
|
|||
--- a/drivers/net/wireless/ath/ath5k/pci.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/pci.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/pci-aspm.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/ath5k_platform.h>
|
||||
#include "../ath.h"
|
||||
#include "ath5k.h"
|
||||
#include "debug.h"
|
||||
@@ -74,7 +75,7 @@ static void ath5k_pci_read_cachesize(str
|
||||
}
|
||||
|
||||
/*
|
||||
- * Read from eeprom
|
||||
+ * Read from eeprom or platform_data
|
||||
*/
|
||||
static bool
|
||||
ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
|
||||
@@ -82,6 +83,19 @@ ath5k_pci_eeprom_read(struct ath_common
|
||||
struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
|
||||
u32 status, timeout;
|
||||
|
||||
+ struct ath5k_platform_data *pdata = NULL;
|
||||
+
|
||||
+ if (ah->pdev)
|
||||
+ pdata = ah->pdev->dev.platform_data;
|
||||
+
|
||||
+ if (pdata && pdata->eeprom_data && pdata->eeprom_data[61] == AR5K_EEPROM_MAGIC_VALUE) {
|
||||
+ if (offset >= ATH5K_PLAT_EEP_MAX_WORDS)
|
||||
+ return false;
|
||||
+
|
||||
+ *data = pdata->eeprom_data[offset];
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Initialize EEPROM access
|
||||
*/
|
||||
@@ -125,6 +139,16 @@ static int ath5k_pci_eeprom_read_mac(str
|
||||
u16 data;
|
||||
int octet;
|
||||
|
||||
+ struct ath5k_platform_data *pdata = NULL;
|
||||
+
|
||||
+ if (ah->pdev)
|
||||
+ pdata = ah->pdev->dev.platform_data;
|
||||
+
|
||||
+ if (pdata && pdata->macaddr) {
|
||||
+ memcpy(mac, pdata->macaddr, ETH_ALEN);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
AR5K_EEPROM_READ(0x20, data);
|
||||
|
||||
for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
|
|
@ -0,0 +1,113 @@
|
|||
This adds a bwmode debugfs file which can be used to set alternate
|
||||
channel operating bandwidths. Only tested with AR5413 and only at
|
||||
5 and 20 mhz channels.
|
||||
|
||||
Signed-off-by: Pat Erley <pat-lkml at erley.org>
|
||||
---
|
||||
Other devices will need to be added to the switch in write_file_bwmode
|
||||
|
||||
drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++
|
||||
1 files changed, 86 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/debug.c
|
||||
@@ -813,6 +813,89 @@ static const struct file_operations fops
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
+/* debugfs: bwmode */
|
||||
+
|
||||
+static ssize_t read_file_bwmode(struct file *file, char __user *user_buf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct ath5k_hw *ah = file->private_data;
|
||||
+ char buf[15];
|
||||
+ unsigned int len = 0;
|
||||
+
|
||||
+ int cur_ah_bwmode = ah->ah_bwmode;
|
||||
+
|
||||
+#define print_selected(MODE, LABEL) \
|
||||
+ if (cur_ah_bwmode == MODE) \
|
||||
+ len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \
|
||||
+ else \
|
||||
+ len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \
|
||||
+ len += snprintf(buf+len, sizeof(buf)-len, " ");
|
||||
+
|
||||
+ print_selected(AR5K_BWMODE_5MHZ, "5");
|
||||
+ print_selected(AR5K_BWMODE_10MHZ, "10");
|
||||
+ print_selected(AR5K_BWMODE_DEFAULT, "20");
|
||||
+ print_selected(AR5K_BWMODE_40MHZ, "40");
|
||||
+#undef print_selected
|
||||
+
|
||||
+ len += snprintf(buf+len, sizeof(buf)-len, "\n");
|
||||
+
|
||||
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
+}
|
||||
+
|
||||
+static ssize_t write_file_bwmode(struct file *file,
|
||||
+ const char __user *userbuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct ath5k_hw *ah = file->private_data;
|
||||
+ char buf[3];
|
||||
+ int bw = 20;
|
||||
+ int tobwmode = AR5K_BWMODE_DEFAULT;
|
||||
+
|
||||
+ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ /* TODO: Add check for active interface */
|
||||
+
|
||||
+ if(strncmp(buf, "5", 1) == 0 ) {
|
||||
+ tobwmode = AR5K_BWMODE_5MHZ;
|
||||
+ bw = 5;
|
||||
+ } else if ( strncmp(buf, "10", 2) == 0 ) {
|
||||
+ tobwmode = AR5K_BWMODE_10MHZ;
|
||||
+ bw = 10;
|
||||
+ } else if ( strncmp(buf, "20", 2) == 0 ) {
|
||||
+ tobwmode = AR5K_BWMODE_DEFAULT;
|
||||
+ bw = 20;
|
||||
+ } else if ( strncmp(buf, "40", 2) == 0 ) {
|
||||
+ tobwmode = AR5K_BWMODE_40MHZ;
|
||||
+ bw = 40;
|
||||
+ } else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n",
|
||||
+ bw, tobwmode);
|
||||
+
|
||||
+ switch (ah->ah_radio) {
|
||||
+ /* TODO: only define radios that actually support 5/10mhz channels */
|
||||
+ case AR5K_RF5413: case AR5K_RF5110: case AR5K_RF5111: case AR5K_RF5112: case AR5K_RF2413: case AR5K_RF2316: case AR5K_RF2317: case AR5K_RF2425:
|
||||
+ if(ah->ah_bwmode != tobwmode) {
|
||||
+ mutex_lock(&ah->lock);
|
||||
+ ah->ah_bwmode = tobwmode;
|
||||
+ mutex_unlock(&ah->lock);
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations fops_bwmode = {
|
||||
+ .read = read_file_bwmode,
|
||||
+ .write = write_file_bwmode,
|
||||
+ .open = simple_open,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .llseek = default_llseek,
|
||||
+};
|
||||
|
||||
/* debugfs: queues etc */
|
||||
|
||||
@@ -904,6 +987,9 @@ ath5k_debug_init_device(struct ath5k_hw
|
||||
debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
|
||||
&fops_beacon);
|
||||
|
||||
+ debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah,
|
||||
+ &fops_bwmode);
|
||||
+
|
||||
debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
|
||||
|
||||
debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
|
|
@ -0,0 +1,10 @@
|
|||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -995,6 +995,7 @@ static const struct net_device_ops ieee8
|
||||
static void ieee80211_if_setup(struct net_device *dev)
|
||||
{
|
||||
ether_setup(dev);
|
||||
+ dev->tx_queue_len = 32;
|
||||
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
|
||||
netdev_attach_ops(dev, &ieee80211_dataif_ops);
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
|
|
@ -0,0 +1,393 @@
|
|||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -839,6 +839,9 @@ enum mac80211_rx_flags {
|
||||
* @signal: signal strength when receiving this frame, either in dBm, in dB or
|
||||
* unspecified depending on the hardware capabilities flags
|
||||
* @IEEE80211_HW_SIGNAL_*
|
||||
+ * @chains: bitmask of receive chains for which separate signal strength
|
||||
+ * values were filled.
|
||||
+ * @chain_signal: per-chain signal strength, same format as @signal
|
||||
* @antenna: antenna used
|
||||
* @rate_idx: index of data rate into band's supported rates or MCS index if
|
||||
* HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
|
||||
@@ -870,6 +873,8 @@ struct ieee80211_rx_status {
|
||||
u8 band;
|
||||
u8 antenna;
|
||||
s8 signal;
|
||||
+ u8 chains;
|
||||
+ s8 chain_signal[4];
|
||||
u8 ampdu_delimiter_crc;
|
||||
u8 vendor_radiotap_align;
|
||||
u8 vendor_radiotap_oui[3];
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -342,6 +342,11 @@ struct sta_info {
|
||||
int last_signal;
|
||||
struct ewma avg_signal;
|
||||
int last_ack_signal;
|
||||
+
|
||||
+ u8 chains;
|
||||
+ s8 chain_signal_last[4];
|
||||
+ struct ewma chain_signal_avg[4];
|
||||
+
|
||||
/* Plus 1 for non-QoS frames */
|
||||
__le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -1383,6 +1383,7 @@ ieee80211_rx_h_sta_process(struct ieee80
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
+ int i;
|
||||
|
||||
if (!sta)
|
||||
return RX_CONTINUE;
|
||||
@@ -1433,6 +1434,19 @@ ieee80211_rx_h_sta_process(struct ieee80
|
||||
ewma_add(&sta->avg_signal, -status->signal);
|
||||
}
|
||||
|
||||
+ if (status->chains) {
|
||||
+ sta->chains = status->chains;
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ int signal = status->chain_signal[i];
|
||||
+
|
||||
+ if (!(status->chains & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
+ sta->chain_signal_last[i] = signal;
|
||||
+ ewma_add(&sta->chain_signal_avg[i], -signal);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Change STA power saving mode only at the end of a frame
|
||||
* exchange sequence.
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -353,6 +353,8 @@ struct sta_info *sta_info_alloc(struct i
|
||||
do_posix_clock_monotonic_gettime(&uptime);
|
||||
sta->last_connected = uptime.tv_sec;
|
||||
ewma_init(&sta->avg_signal, 1024, 8);
|
||||
+ for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
||||
+ ewma_init(&sta->chain_signal_avg[i], 1024, 8);
|
||||
|
||||
if (sta_prepare_rate_control(local, sta, gfp)) {
|
||||
kfree(sta);
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -721,6 +721,8 @@ struct station_parameters {
|
||||
* @STATION_INFO_LOCAL_PM: @local_pm filled
|
||||
* @STATION_INFO_PEER_PM: @peer_pm filled
|
||||
* @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
|
||||
+ * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
|
||||
+ * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
|
||||
*/
|
||||
enum station_info_flags {
|
||||
STATION_INFO_INACTIVE_TIME = 1<<0,
|
||||
@@ -749,6 +751,8 @@ enum station_info_flags {
|
||||
STATION_INFO_NONPEER_PM = 1<<23,
|
||||
STATION_INFO_RX_BYTES64 = 1<<24,
|
||||
STATION_INFO_TX_BYTES64 = 1<<25,
|
||||
+ STATION_INFO_CHAIN_SIGNAL = 1<<26,
|
||||
+ STATION_INFO_CHAIN_SIGNAL_AVG = 1<<27,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -842,6 +846,9 @@ struct sta_bss_parameters {
|
||||
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
|
||||
* @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
|
||||
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
|
||||
+ * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg
|
||||
+ * @chain_signal: per-chain signal strength of last received packet in dBm
|
||||
+ * @chain_signal_avg: per-chain signal strength average in dBm
|
||||
* @txrate: current unicast bitrate from this station
|
||||
* @rxrate: current unicast bitrate to this station
|
||||
* @rx_packets: packets received from this station
|
||||
@@ -877,6 +884,11 @@ struct station_info {
|
||||
u8 plink_state;
|
||||
s8 signal;
|
||||
s8 signal_avg;
|
||||
+
|
||||
+ u8 chains;
|
||||
+ s8 chain_signal[4];
|
||||
+ s8 chain_signal_avg[4];
|
||||
+
|
||||
struct rate_info txrate;
|
||||
struct rate_info rxrate;
|
||||
u32 rx_packets;
|
||||
--- a/drivers/net/wireless/ath/ath9k/mac.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/mac.h
|
||||
@@ -133,12 +133,8 @@ struct ath_rx_status {
|
||||
u8 rs_rate;
|
||||
u8 rs_antenna;
|
||||
u8 rs_more;
|
||||
- int8_t rs_rssi_ctl0;
|
||||
- int8_t rs_rssi_ctl1;
|
||||
- int8_t rs_rssi_ctl2;
|
||||
- int8_t rs_rssi_ext0;
|
||||
- int8_t rs_rssi_ext1;
|
||||
- int8_t rs_rssi_ext2;
|
||||
+ int8_t rs_rssi_ctl[3];
|
||||
+ int8_t rs_rssi_ext[3];
|
||||
u8 rs_isaggr;
|
||||
u8 rs_moreaggr;
|
||||
u8 rs_num_delims;
|
||||
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
||||
@@ -937,6 +937,7 @@ static int ath9k_rx_skb_preprocess(struc
|
||||
bool *decrypt_error)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
+ int i, j;
|
||||
|
||||
/*
|
||||
* everything but the rate is checked here, the rate check is done
|
||||
@@ -962,6 +963,20 @@ static int ath9k_rx_skb_preprocess(struc
|
||||
if (rx_stats->rs_moreaggr)
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
+ for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
|
||||
+ s8 rssi;
|
||||
+
|
||||
+ if (!(ah->rxchainmask & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
+ rssi = rx_stats->rs_rssi_ctl[i];
|
||||
+ if (rssi != ATH9K_RSSI_BAD) {
|
||||
+ rx_status->chains |= BIT(j);
|
||||
+ rx_status->chain_signal[j] = ah->noise + rssi;
|
||||
+ }
|
||||
+ j++;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1070,7 +1085,7 @@ static int ath_process_fft(struct ath_so
|
||||
fft_sample.tlv.length = __cpu_to_be16(length);
|
||||
|
||||
fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
|
||||
- fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
|
||||
+ fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
|
||||
fft_sample.noise = ah->noise;
|
||||
|
||||
switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||
@@ -475,12 +475,12 @@ int ath9k_hw_process_rxdesc_edma(struct
|
||||
|
||||
/* XXX: Keycache */
|
||||
rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
|
||||
- rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
|
||||
- rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
|
||||
- rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
|
||||
- rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
|
||||
- rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
|
||||
- rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
|
||||
+ rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
|
||||
+ rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
|
||||
+ rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);
|
||||
+ rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
|
||||
+ rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
|
||||
+ rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);
|
||||
|
||||
if (rxsp->status11 & AR_RxKeyIdxValid)
|
||||
rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
|
||||
--- a/drivers/net/wireless/ath/ath9k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/mac.c
|
||||
@@ -553,25 +553,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a
|
||||
|
||||
if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
|
||||
rs->rs_rssi = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
|
||||
- rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
|
||||
+ rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
|
||||
} else {
|
||||
rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
|
||||
- rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
|
||||
+ rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
|
||||
AR_RxRSSIAnt00);
|
||||
- rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
|
||||
+ rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
|
||||
AR_RxRSSIAnt01);
|
||||
- rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
|
||||
+ rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
|
||||
AR_RxRSSIAnt02);
|
||||
- rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
|
||||
+ rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
|
||||
AR_RxRSSIAnt10);
|
||||
- rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
|
||||
+ rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
|
||||
AR_RxRSSIAnt11);
|
||||
- rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
|
||||
+ rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
|
||||
AR_RxRSSIAnt12);
|
||||
}
|
||||
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
|
||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||
@@ -940,12 +940,12 @@ void ath_debug_stat_rx(struct ath_softc
|
||||
#ifdef CONFIG_ATH9K_MAC_DEBUG
|
||||
spin_lock(&sc->debug.samp_lock);
|
||||
RX_SAMP_DBG(jiffies) = jiffies;
|
||||
- RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
|
||||
- RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1;
|
||||
- RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2;
|
||||
- RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0;
|
||||
- RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1;
|
||||
- RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2;
|
||||
+ RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl[0];
|
||||
+ RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl[1];
|
||||
+ RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl[2];
|
||||
+ RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext[0];
|
||||
+ RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext[1];
|
||||
+ RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext[2];
|
||||
RX_SAMP_DBG(antenna) = rs->rs_antenna;
|
||||
RX_SAMP_DBG(rssi) = rs->rs_rssi;
|
||||
RX_SAMP_DBG(rate) = rs->rs_rate;
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -1918,6 +1918,8 @@ enum nl80211_sta_bss_param {
|
||||
* @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
|
||||
* @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
|
||||
* non-peer STA
|
||||
+ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
|
||||
+ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||
*/
|
||||
@@ -1947,6 +1949,8 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_NONPEER_PM,
|
||||
NL80211_STA_INFO_RX_BYTES64,
|
||||
NL80211_STA_INFO_TX_BYTES64,
|
||||
+ NL80211_STA_INFO_CHAIN_SIGNAL,
|
||||
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -3082,6 +3082,32 @@ static bool nl80211_put_sta_rate(struct
|
||||
return true;
|
||||
}
|
||||
|
||||
+static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
|
||||
+ int id)
|
||||
+{
|
||||
+ void *attr;
|
||||
+ int i = 0;
|
||||
+
|
||||
+ if (!mask)
|
||||
+ return true;
|
||||
+
|
||||
+ attr = nla_nest_start(msg, id);
|
||||
+ if (!attr)
|
||||
+ return false;
|
||||
+
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ if (!(mask & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
+ if (nla_put_u8(msg, i, signal[i]))
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ nla_nest_end(msg, attr);
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
int flags,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
@@ -3153,6 +3179,18 @@ static int nl80211_send_station(struct s
|
||||
default:
|
||||
break;
|
||||
}
|
||||
+ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
|
||||
+ if (!nl80211_put_signal(msg, sinfo->chains,
|
||||
+ sinfo->chain_signal,
|
||||
+ NL80211_STA_INFO_CHAIN_SIGNAL))
|
||||
+ goto nla_put_failure;
|
||||
+ }
|
||||
+ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
|
||||
+ if (!nl80211_put_signal(msg, sinfo->chains,
|
||||
+ sinfo->chain_signal_avg,
|
||||
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
|
||||
+ goto nla_put_failure;
|
||||
+ }
|
||||
if (sinfo->filled & STATION_INFO_TX_BITRATE) {
|
||||
if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
|
||||
NL80211_STA_INFO_TX_BITRATE))
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -445,6 +445,7 @@ static void sta_set_sinfo(struct sta_inf
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct timespec uptime;
|
||||
+ int i;
|
||||
|
||||
sinfo->generation = sdata->local->sta_generation;
|
||||
|
||||
@@ -484,6 +485,17 @@ static void sta_set_sinfo(struct sta_inf
|
||||
sinfo->signal = (s8)sta->last_signal;
|
||||
sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
|
||||
}
|
||||
+ if (sta->chains) {
|
||||
+ sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
|
||||
+ STATION_INFO_CHAIN_SIGNAL_AVG;
|
||||
+
|
||||
+ sinfo->chains = sta->chains;
|
||||
+ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
|
||||
+ sinfo->chain_signal[i] = sta->chain_signal_last[i];
|
||||
+ sinfo->chain_signal_avg[i] =
|
||||
+ (s8) -ewma_read(&sta->chain_signal_avg[i]);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
|
||||
sta_set_rate_info_rx(sta, &sinfo->rxrate);
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
@@ -164,8 +164,8 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
return;
|
||||
}
|
||||
|
||||
- ard.rssi = rs->rs_rssi_ctl0;
|
||||
- ard.ext_rssi = rs->rs_rssi_ext0;
|
||||
+ ard.rssi = rs->rs_rssi_ctl[0];
|
||||
+ ard.ext_rssi = rs->rs_rssi_ext[0];
|
||||
|
||||
/*
|
||||
* hardware stores this as 8 bit signed value.
|
||||
--- a/drivers/net/wireless/ath/ath9k/antenna.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
|
||||
@@ -546,14 +546,14 @@ void ath_ant_comb_scan(struct ath_softc
|
||||
struct ath_ant_comb *antcomb = &sc->ant_comb;
|
||||
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
|
||||
int curr_main_set;
|
||||
- int main_rssi = rs->rs_rssi_ctl0;
|
||||
- int alt_rssi = rs->rs_rssi_ctl1;
|
||||
+ int main_rssi = rs->rs_rssi_ctl[0];
|
||||
+ int alt_rssi = rs->rs_rssi_ctl[1];
|
||||
int rx_ant_conf, main_ant_conf;
|
||||
bool short_scan = false;
|
||||
|
||||
- rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
|
||||
+ rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
- main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
|
||||
+ main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
|
||||
/* Record packet only when both main_rssi and alt_rssi is positive */
|
|
@ -0,0 +1,162 @@
|
|||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -978,6 +978,7 @@ enum ieee80211_smps_mode {
|
||||
*
|
||||
* @power_level: requested transmit power (in dBm), backward compatibility
|
||||
* value only that is set to the minimum of all interfaces
|
||||
+ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
|
||||
*
|
||||
* @channel: the channel to tune to
|
||||
* @channel_type: the channel (HT) type
|
||||
@@ -1000,6 +1001,7 @@ struct ieee80211_conf {
|
||||
u32 flags;
|
||||
int power_level, dynamic_ps_timeout;
|
||||
int max_sleep_period;
|
||||
+ int max_antenna_gain;
|
||||
|
||||
u16 listen_interval;
|
||||
u8 ps_dtim_period;
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1116,6 +1116,7 @@ struct ieee80211_local {
|
||||
int dynamic_ps_forced_timeout;
|
||||
|
||||
int user_power_level; /* in dBm, for all interfaces */
|
||||
+ int user_antenna_gain; /* in dBi */
|
||||
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -1654,6 +1654,8 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_STA_CAPABILITY,
|
||||
NL80211_ATTR_STA_EXT_CAPABILITY,
|
||||
|
||||
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -370,6 +370,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
|
||||
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
|
||||
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -1705,6 +1706,22 @@ static int nl80211_set_wiphy(struct sk_b
|
||||
if (result)
|
||||
goto bad_res;
|
||||
}
|
||||
+
|
||||
+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
|
||||
+ int idx, dbi = 0;
|
||||
+
|
||||
+ if (!rdev->ops->set_antenna_gain) {
|
||||
+ result = -EOPNOTSUPP;
|
||||
+ goto bad_res;
|
||||
+ }
|
||||
+
|
||||
+ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
|
||||
+ dbi = nla_get_u32(info->attrs[idx]);
|
||||
+
|
||||
+ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
|
||||
+ if (result)
|
||||
+ goto bad_res;
|
||||
+ }
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
|
||||
info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2212,6 +2212,19 @@ static int ieee80211_get_tx_power(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
|
||||
+{
|
||||
+ struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
+
|
||||
+ if (dbi < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ local->user_antenna_gain = dbi;
|
||||
+ ieee80211_hw_config(local, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *addr)
|
||||
{
|
||||
@@ -3375,6 +3388,7 @@ struct cfg80211_ops mac80211_config_ops
|
||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||
.set_tx_power = ieee80211_set_tx_power,
|
||||
.get_tx_power = ieee80211_get_tx_power,
|
||||
+ .set_antenna_gain = ieee80211_set_antenna_gain,
|
||||
.set_wds_peer = ieee80211_set_wds_peer,
|
||||
.rfkill_poll = ieee80211_rfkill_poll,
|
||||
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -1862,6 +1862,7 @@ struct cfg80211_gtk_rekey_data {
|
||||
* (as advertised by the nl80211 feature flag.)
|
||||
* @get_tx_power: store the current TX power into the dbm variable;
|
||||
* return 0 if successful
|
||||
+ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
|
||||
*
|
||||
* @set_wds_peer: set the WDS peer for a WDS interface
|
||||
*
|
||||
@@ -2071,6 +2072,7 @@ struct cfg80211_ops {
|
||||
enum nl80211_tx_power_setting type, int mbm);
|
||||
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
int *dbm);
|
||||
+ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
|
||||
|
||||
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *addr);
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -101,7 +101,7 @@ static u32 ieee80211_hw_conf_chan(struct
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_channel *chan;
|
||||
u32 changed = 0;
|
||||
- int power;
|
||||
+ int power, ant_gain, max_power;
|
||||
enum nl80211_channel_type channel_type;
|
||||
u32 offchannel_flag;
|
||||
bool scanning = false;
|
||||
@@ -164,8 +164,21 @@ static u32 ieee80211_hw_conf_chan(struct
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
- if (local->hw.conf.power_level != power) {
|
||||
+ max_power = chan->max_reg_power;
|
||||
+ ant_gain = chan->max_antenna_gain;
|
||||
+ if (local->user_antenna_gain > 0) {
|
||||
+ if (local->user_antenna_gain > ant_gain) {
|
||||
+ max_power -= local->user_antenna_gain - ant_gain;
|
||||
+ ant_gain = 0;
|
||||
+ } else
|
||||
+ ant_gain -= local->user_antenna_gain;
|
||||
+ power = min(power, max_power);
|
||||
+ }
|
||||
+
|
||||
+ if (local->hw.conf.power_level != power ||
|
||||
+ local->hw.conf.max_antenna_gain != ant_gain) {
|
||||
changed |= IEEE80211_CONF_CHANGE_POWER;
|
||||
+ local->hw.conf.max_antenna_gain = ant_gain;
|
||||
local->hw.cur_power_level = power;
|
||||
local->hw.conf.power_level = power;
|
||||
}
|
||||
@@ -612,6 +625,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_BW;
|
||||
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
|
||||
+ local->user_antenna_gain = 0;
|
||||
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
@@ -551,6 +551,9 @@ struct ath9k_wow_pattern {
|
||||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
void ath_fill_led_pin(struct ath_softc *sc);
|
||||
+int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
|
||||
+ const char *trigger, bool active_low);
|
||||
+
|
||||
#else
|
||||
static inline void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
@@ -686,6 +689,13 @@ enum spectral_mode {
|
||||
SPECTRAL_CHANSCAN,
|
||||
};
|
||||
|
||||
+struct ath_led {
|
||||
+ struct list_head list;
|
||||
+ struct ath_softc *sc;
|
||||
+ const struct gpio_led *gpio;
|
||||
+ struct led_classdev cdev;
|
||||
+};
|
||||
+
|
||||
struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
@@ -727,9 +737,8 @@ struct ath_softc {
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
- bool led_registered;
|
||||
- char led_name[32];
|
||||
- struct led_classdev led_cdev;
|
||||
+ const char *led_default_trigger;
|
||||
+ struct list_head leds;
|
||||
#endif
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
--- a/drivers/net/wireless/ath/ath9k/gpio.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
|
||||
@@ -24,40 +24,102 @@
|
||||
static void ath_led_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
|
||||
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
|
||||
+ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
|
||||
+ struct ath_softc *sc = led->sc;
|
||||
+
|
||||
+ ath9k_ps_wakeup(sc);
|
||||
+ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
|
||||
+ (brightness != LED_OFF) ^ led->gpio->active_low);
|
||||
+ ath9k_ps_restore(sc);
|
||||
+}
|
||||
+
|
||||
+static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
|
||||
+{
|
||||
+ const struct gpio_led *gpio = led->gpio;
|
||||
+ int ret;
|
||||
+
|
||||
+ led->cdev.name = gpio->name;
|
||||
+ led->cdev.default_trigger = gpio->default_trigger;
|
||||
+ led->cdev.brightness_set = ath_led_brightness;
|
||||
+
|
||||
+ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ led->sc = sc;
|
||||
+ list_add(&led->list, &sc->leds);
|
||||
+
|
||||
+ /* Configure gpio for output */
|
||||
+ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
|
||||
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
+
|
||||
+ /* LED off */
|
||||
+ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
|
||||
+ const char *trigger, bool active_low)
|
||||
+{
|
||||
+ struct ath_led *led;
|
||||
+ struct gpio_led *gpio;
|
||||
+ char *_name;
|
||||
+ int ret;
|
||||
+
|
||||
+ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!led)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ led->gpio = gpio = (struct gpio_led *) (led + 1);
|
||||
+ _name = (char *) (led->gpio + 1);
|
||||
+
|
||||
+ strcpy(_name, name);
|
||||
+ gpio->name = _name;
|
||||
+ gpio->gpio = gpio_num;
|
||||
+ gpio->active_low = active_low;
|
||||
+ gpio->default_trigger = trigger;
|
||||
+
|
||||
+ ret = ath_add_led(sc, led);
|
||||
+ if (unlikely(ret < 0))
|
||||
+ kfree(led);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
- if (!sc->led_registered)
|
||||
- return;
|
||||
+ struct ath_led *led;
|
||||
|
||||
- ath_led_brightness(&sc->led_cdev, LED_OFF);
|
||||
- led_classdev_unregister(&sc->led_cdev);
|
||||
+ while (!list_empty(&sc->leds)) {
|
||||
+ led = list_first_entry(&sc->leds, struct ath_led, list);
|
||||
+ list_del(&led->list);
|
||||
+ ath_led_brightness(&led->cdev, LED_OFF);
|
||||
+ led_classdev_unregister(&led->cdev);
|
||||
+ kfree(led);
|
||||
+ }
|
||||
}
|
||||
|
||||
void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
- int ret;
|
||||
+ char led_name[32];
|
||||
+ const char *trigger;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&sc->leds);
|
||||
|
||||
if (AR_SREV_9100(sc->sc_ah))
|
||||
return;
|
||||
|
||||
- if (!led_blink)
|
||||
- sc->led_cdev.default_trigger =
|
||||
- ieee80211_get_radio_led_name(sc->hw);
|
||||
-
|
||||
- snprintf(sc->led_name, sizeof(sc->led_name),
|
||||
- "ath9k-%s", wiphy_name(sc->hw->wiphy));
|
||||
- sc->led_cdev.name = sc->led_name;
|
||||
- sc->led_cdev.brightness_set = ath_led_brightness;
|
||||
+ snprintf(led_name, sizeof(led_name), "ath9k-%s",
|
||||
+ wiphy_name(sc->hw->wiphy));
|
||||
|
||||
- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
|
||||
- if (ret < 0)
|
||||
- return;
|
||||
+ if (led_blink)
|
||||
+ trigger = sc->led_default_trigger;
|
||||
+ else
|
||||
+ trigger = ieee80211_get_radio_led_name(sc->hw);
|
||||
|
||||
- sc->led_registered = true;
|
||||
+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
|
||||
}
|
||||
|
||||
void ath_fill_led_pin(struct ath_softc *sc)
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -870,7 +870,7 @@ int ath9k_init_device(u16 devid, struct
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
/* must be initialized before ieee80211_register_hw */
|
||||
- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
|
||||
+ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
|
||||
IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
|
||||
ARRAY_SIZE(ath9k_tpt_blink));
|
||||
#endif
|
||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||
@@ -1482,6 +1482,61 @@ static const struct file_operations fops
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_MAC80211_LEDS
|
||||
+
|
||||
+static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct ath_softc *sc = file->private_data;
|
||||
+ char buf[32], *str, *name, *c;
|
||||
+ ssize_t len;
|
||||
+ unsigned int gpio;
|
||||
+ bool active_low = false;
|
||||
+
|
||||
+ len = min(count, sizeof(buf) - 1);
|
||||
+ if (copy_from_user(buf, ubuf, len))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ buf[len] = '\0';
|
||||
+ name = strchr(buf, ',');
|
||||
+ if (!name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ *(name++) = 0;
|
||||
+ if (!*name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ c = strchr(name, '\n');
|
||||
+ if (c)
|
||||
+ *c = 0;
|
||||
+
|
||||
+ str = buf;
|
||||
+ if (*str == '!') {
|
||||
+ str++;
|
||||
+ active_low = true;
|
||||
+ }
|
||||
+
|
||||
+ if (kstrtouint(str, 0, &gpio) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations fops_gpio_led = {
|
||||
+ .write = write_file_gpio_led,
|
||||
+ .open = simple_open,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .llseek = default_llseek,
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_ATH9K_MAC_DEBUG
|
||||
|
||||
void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
|
||||
@@ -2115,6 +2170,10 @@ int ath9k_init_debug(struct ath_hw *ah)
|
||||
&fops_eeprom);
|
||||
debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
|
||||
sc, &fops_chanbw);
|
||||
+#ifdef CONFIG_MAC80211_LEDS
|
||||
+ debugfs_create_file("gpio_led", S_IWUSR,
|
||||
+ sc->debug.debugfs_phy, sc, &fops_gpio_led);
|
||||
+#endif
|
||||
debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_dma);
|
||||
debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
|
|
@ -0,0 +1,28 @@
|
|||
--- a/drivers/net/wireless/ath/ath9k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/mac.c
|
||||
@@ -689,7 +689,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
|
||||
{
|
||||
#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
- u32 mac_status, last_mac_status = 0;
|
||||
+ u32 mac_status = 0, last_mac_status = 0;
|
||||
int i;
|
||||
|
||||
/* Enable access to the DMA observation bus */
|
||||
@@ -719,6 +719,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
+ if (!AR_SREV_9300_20_OR_LATER(ah) &&
|
||||
+ (mac_status & 0x700) == 0) {
|
||||
+ /*
|
||||
+ * DMA is idle but the MAC is still stuck
|
||||
+ * processing events
|
||||
+ */
|
||||
+ *reset = true;
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
ath_err(common,
|
||||
"DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
|
||||
AH_RX_STOP_DMA_TIMEOUT / 1000,
|
Loading…
Reference in New Issue