* [PATCH] rfkill: fix rfkill_set_states() to set the hw state
From: Alan Jenkins @ 2009-07-12 16:03 UTC (permalink / raw)
To: alan-jenkins, johannes; +Cc: linux-wireless
The point of this function is to set the software and hardware state at
the same time. When I tried to use it, I found it was only setting the
software state.
Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
---
net/rfkill/core.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 79693fe..db9948e 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -549,6 +549,10 @@ void rfkill_set_states(struct rfkill *rfkill, bool
sw, bool hw)
swprev = !!(rfkill->state & RFKILL_BLOCK_SW);
hwprev = !!(rfkill->state & RFKILL_BLOCK_HW);
__rfkill_set_sw_state(rfkill, sw);
+ if (hw)
+ rfkill->state |= RFKILL_BLOCK_HW;
+ else
+ rfkill->state &= ~RFKILL_BLOCK_HW;
spin_unlock_irqrestore(&rfkill->lock, flags);
--
1.5.4.3
^ permalink raw reply related
* Re: [Orinoco-devel] orinoco-usb in 2.6.31?
From: David Gerard @ 2009-07-12 15:09 UTC (permalink / raw)
To: orinoco-devel, linux-wireless
In-Reply-To: <20090712105807.g85wo8lpgk04k8gk-cebfxv@webmail.spamcop.net>
2009/7/12 Pavel Roskin <proski@gnu.org>:
> I have an impression that orinoco-usb should be submitted to the staging
> tree. Perhaps its symbols should be renamed to allow it to coexist with the
> plain orinoco driver, even if both are linked into the kernel.
> I was hoping that we would reorganize the orinoco driver to allow
> orinoco-usb to be one of its frontends, but it's not happening. All the
> efforts that go into orinoco-usb is keeping it up-to-date with the kernel.
It's unspeakably horrible and only us old W200 owners are keeping
interest up. I've probably posted this here before, but even the
Windows driver doesn't work properly:
http://forums11.itrc.hp.com/service/forums/bizsupport/questionanswer.do?admit=109447626+1247092556853+28353475&threadId=1072085
If you use the latest driver, 1.00F, on XP, it blue-screens if it even
*sees* an 802.11n access point in range! You have to downgrade to
1.00C, so no WPA on Windows either.
It wouldn't take much to make the Linux driver better, even as is :-)
All it needs now is redistributable firmware.
- d.
^ permalink raw reply
* Re: ath5k and Atheros AR242x - No scan results
From: Nick Kossifidis @ 2009-07-12 15:08 UTC (permalink / raw)
To: Joel Roth; +Cc: linux-wireless
In-Reply-To: <20090712112340.GA3315@sprite>
2009/7/12 Joel Roth <joelz@pobox.com>:
> On Tue, Jun 30, 2009 at 07:09:16AM -1000, Joel Roth wrote:
>> Hello all,
>>
>> I'd appreciate some help troubleshooting my wireless connection.
>>
>> I have a Toshiba Satellite L305 series laptop running Debian
>> sid with a recent, stock Debian kernel version 2.6.29-2-486.
>>
>> $ lspci | grep Atheros
>>
>> 05:00.0 Ethernet controller: Atheros Communications Inc. AR242x 802.11abg Wireless PCI Express Adapter (rev 01)
>>
>> I am seeking to connect to a D-Link 614+ wireless router.
>> For initial testing, the AP is unencrypted, unsecured.
>>
>> My wife's G3 i-Book with AfterTheMac USB wireless adapter
>> connected just fine, on the first try.
>>
>> I believe I have the modules I should have:
>>
>> $ lsmod | grep 80211
>> mac80211 139680 1 ath5k
>> cfg80211 21576 2 ath5k,mac80211
>>
>> My wireless network interface is present:
>>
>> $ iwconfig wlan0
>>
>> wlan0 IEEE 802.11 ESSID:""
>> Mode:Managed Frequency:2.412 GHz Access Point: Not-Associated
>> Tx-Power=0 dBm
>> Retry min limit:7 RTS thr:off Fragment thr=2352 B
>> Link Quality:0 Signal level:0 Noise level:0
>> Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
>> Tx excessive retries:0 Invalid misc:0 Missed beacon:0
>>
>> $ ifconfig wlan0
>>
>> wlan0 Link encap:Ethernet HWaddr 00:21:63:82:82:40
>> UP BROADCAST MULTICAST MTU:1500 Metric:1
>> RX packets:0 errors:0 dropped:0 overruns:0 frame:0
>> TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
>> collisions:0 txqueuelen:1000
>> RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
>>
>>
>> However, I don't find the D-Link 614+:
>>
>> $ iwlist wlan0 scan
>>
>> wlan0 No scan results
>>
>> And of course, dhclient fails to find a server.
>>
>> Am I missing something? What could I try next?
>> I'd appreciate any pointers.
>>
>> Thanks.
>
> Okay, I'm back with a new kernel 2.6.30.1 and the latest
> ath5k. Here are my basic diagnostics data.
>
> $ iwlist wlan0 scan
>
> wlan0 No scan results
>
> $ iwlist wlan0 ap
>
> wlan0 Interface doesn't have a list of Peers/Access-Points
>
> $ iwconfig wlan0
>
> wlan0 IEEE 802.11bg ESSID:""
> Mode:Managed Frequency:2.412 GHz Access Point: Not-Associated
> Tx-Power=27 dBm
> Retry min limit:7 RTS thr:off Fragment thr:off
> Power Management:off
> Link Quality:0 Signal level:0 Noise level:0
> Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
> Tx excessive retries:0 Invalid misc:0 Missed beacon:0
>
> $ ifconfig wlan0
>
> wlan0 Link encap:Ethernet HWaddr 00:21:63:82:82:40
> UP BROADCAST MULTICAST MTU:1500 Metric:1
> RX packets:0 errors:0 dropped:0 overruns:0 frame:0
> TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
> collisions:0 txqueuelen:1000
> RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
>
> dmesg highlights
>
> [ 4.884157] ath5k 0000:05:00.0: enabling device (0000 -> 0002)
> [ 4.884223] ath5k 0000:05:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
> [ 4.884283] ath5k 0000:05:00.0: setting latency timer to 64
> [ 4.884326] ath5k 0000:05:00.0: registered as 'phy0'
> [ 6.411392] ath5k phy0: Atheros AR2425 chip found (MAC: 0xe2, PHY: 0x70)
> [ 337.543014] ADDRCONF(NETDEV_UP): wlan0: link is not ready
>
> I compiled the kernel with debugfs support for wireless. Can someone
> point me to helpful docs in setting this up.
>
> Also, is there a chance that another driver would serve me better?
>
> Regards,
>
> --
> Joel Roth
O.K. can you try madwifi so that we can eliminate the possibility of a
hw failure ?
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* Re: [Orinoco-devel] orinoco-usb in 2.6.31?
From: Pavel Roskin @ 2009-07-12 14:58 UTC (permalink / raw)
To: Dave; +Cc: orinoco-devel, David Gerard, linux-wireless
In-Reply-To: <4A58FC5C.8060204@gmail.com>
Quoting Dave <kilroyd@googlemail.com>:
> The rebasing was a little painful due to all the changes that have been
> happening on orinoco. However I think I'm done.
I have an impression that orinoco-usb should be submitted to the
staging tree. Perhaps its symbols should be renamed to allow it to
coexist with the plain orinoco driver, even if both are linked into
the kernel.
I was hoping that we would reorganize the orinoco driver to allow
orinoco-usb to be one of its frontends, but it's not happening. All
the efforts that go into orinoco-usb is keeping it up-to-date with the
kernel.
--
Regards,
Pavel Roskin
^ permalink raw reply
* Re: iwlwifi 4965 uCode available
From: Helmut Schaa @ 2009-07-12 12:45 UTC (permalink / raw)
To: reinette chatre; +Cc: linux-wireless, ipw3945-devel
In-Reply-To: <1247174482.17896.1304.camel@rc-desk>
Am Donnerstag, 9. Juli 2009 schrieb reinette chatre:
> Version 228.61.2.24 of uCode for Intel Wireless WiFi Link 4965AGN is now
> available for download from
> http://intellinuxwireless.org/?n=Downloads
The new ucode seems to cause fw restarts every now and then (together
with wireless-testing).
iwlagn 0000:10:00.0: Microcode SW error detected. Restarting 0x82000000.
I couldn't figure out how to reproduce this but it happened a few times
now since I switched to the new ucode.
Should I load iwlagn with some special debug flags?
Helmut
^ permalink raw reply
* [PATCH 1/2] [compat-2.6] Update compat.diff for master-2009-07-10
From: Hauke Mehrtens @ 2009-07-12 11:26 UTC (permalink / raw)
To: lrodriguez; +Cc: linux-wireless, Hauke Mehrtens
This is now compiling with kernel at least 2.6.26 to 2.6.30.
MAC80211_DRIVER_API_TRACER is only working with kernel >= 2.6.30.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
compat/compat-2.6.28.c | 53 +++++++++++++++++++++++++++++++++++++++++++
compat/compat-2.6.28.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
compat/compat-2.6.30.h | 9 ++++++-
compat/compat.diff | 25 ++++++++++++++++++--
4 files changed, 142 insertions(+), 4 deletions(-)
diff --git a/compat/compat-2.6.28.c b/compat/compat-2.6.28.c
index 53856d0..7abd50d 100644
--- a/compat/compat-2.6.28.c
+++ b/compat/compat-2.6.28.c
@@ -28,4 +28,57 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
}
EXPORT_SYMBOL_GPL(pci_ioremap_bar);
+static unsigned long round_jiffies_common(unsigned long j, int cpu,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ /*
+ * We don't want all cpus firing their timers at once hitting the
+ * same lock or cachelines, so we skew each extra cpu with an extra
+ * 3 jiffies. This 3 jiffies came originally from the mm/ code which
+ * already did this.
+ * The skew is done by adding 3*cpunr, then round, then subtract this
+ * extra offset again.
+ */
+ j += cpu * 3;
+
+ rem = j % HZ;
+
+ /*
+ * If the target jiffie is just after a whole second (which can happen
+ * due to delays of the timer irq, long irq off times etc etc) then
+ * we should round down to the whole second, not up. Use 1/4th second
+ * as cutoff for this rounding as an extreme upper bound for this.
+ * But never round down if @force_up is set.
+ */
+ if (rem < HZ/4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+
+ /* now that we have rounded, subtract the extra skew again */
+ j -= cpu * 3;
+
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+
+/**
+ * round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies() except that it will never
+ * round down. This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, raw_smp_processor_id(), true);
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up);
+
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) */
diff --git a/compat/compat-2.6.28.h b/compat/compat-2.6.28.h
index cb956b7..6f7760e 100644
--- a/compat/compat-2.6.28.h
+++ b/compat/compat-2.6.28.h
@@ -92,6 +92,20 @@ static inline void __skb_queue_splice(const struct sk_buff_head *list,
}
/**
+ * skb_queue_splice - join two skb lists, this is designed for stacks
+ * @list: the new list to add
+ * @head: the place to add it in the first list
+ */
+static inline void skb_queue_splice(const struct sk_buff_head *list,
+ struct sk_buff_head *head)
+{
+ if (!skb_queue_empty(list)) {
+ __skb_queue_splice(list, (struct sk_buff *) head, head->next);
+ head->qlen += list->qlen;
+ }
+}
+
+/**
* skb_queue_splice_tail - join two skb lists and reinitialise the emptied list
* @list: the new list to add
* @head: the place to add it in the first list
@@ -109,6 +123,51 @@ static inline void skb_queue_splice_tail_init(struct sk_buff_head *list,
}
} /* From include/linux/skbuff.h */
+struct module;
+struct tracepoint;
+
+struct tracepoint {
+ const char *name; /* Tracepoint name */
+ int state; /* State. */
+ void **funcs;
+} __attribute__((aligned(32))); /*
+ * Aligned on 32 bytes because it is
+ * globally visible and gcc happily
+ * align these on the structure size.
+ * Keep in sync with vmlinux.lds.h.
+ */
+
+#ifndef DECLARE_TRACE
+
+#define TP_PROTO(args...) args
+#define TP_ARGS(args...) args
+
+#define DECLARE_TRACE(name, proto, args) \
+ static inline void _do_trace_##name(struct tracepoint *tp, proto) \
+ { } \
+ static inline void trace_##name(proto) \
+ { } \
+ static inline int register_trace_##name(void (*probe)(proto)) \
+ { \
+ return -ENOSYS; \
+ } \
+ static inline int unregister_trace_##name(void (*probe)(proto)) \
+ { \
+ return -ENOSYS; \
+ }
+
+#define DEFINE_TRACE(name)
+#define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
+#define EXPORT_TRACEPOINT_SYMBOL(name)
+
+static inline void tracepoint_update_probe_range(struct tracepoint *begin,
+ struct tracepoint *end)
+{ }
+
+#endif
+
+unsigned long round_jiffies_up(unsigned long j);
+
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) */
#endif /* LINUX_26_28_COMPAT_H */
diff --git a/compat/compat-2.6.30.h b/compat/compat-2.6.30.h
index 112cf19..6a7c8fb 100644
--- a/compat/compat-2.6.30.h
+++ b/compat/compat-2.6.30.h
@@ -6,7 +6,14 @@
#include <linux/compat_autoconf.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
-/* Nothing ! */
+
+#ifndef TP_PROTO
+#define TP_PROTO(args...) TPPROTO(args)
+#endif
+#ifndef TP_ARGS
+#define TP_ARGS(args...) TPARGS(args)
+#endif
+
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) */
#endif /* LINUX_26_30_COMPAT_H */
diff --git a/compat/compat.diff b/compat/compat.diff
index 4c5c8d6..6214f4a 100644
--- a/compat/compat.diff
+++ b/compat/compat.diff
@@ -413,9 +413,9 @@
rtap_dev->ml_priv = priv;
SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
---- a/drivers/net/wireless/mac80211_hwsim.c 2009-07-08 23:32:17.001186494 -0700
-+++ b/drivers/net/wireless/mac80211_hwsim.c 2009-07-08 23:32:17.065187158 -0700
-@@ -813,16 +813,22 @@
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -814,16 +814,22 @@ static struct device_driver mac80211_hwsim_driver = {
.name = "mac80211_hwsim"
};
@@ -521,6 +521,25 @@
/*
+--- a/net/mac80211/driver-trace.h
++++ b/net/mac80211/driver-trace.h
+@@ -1,7 +1,9 @@
+ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+ #define __MAC80211_DRIVER_TRACE
+
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
+ #include <linux/tracepoint.h>
++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) */
+ #include <net/mac80211.h>
+ #include "ieee80211_i.h"
+
+@@ -645,4 +647,6 @@ TRACE_EVENT(drv_ampdu_action,
+ #define TRACE_INCLUDE_PATH .
+ #undef TRACE_INCLUDE_FILE
+ #define TRACE_INCLUDE_FILE driver-trace
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30))
+ #include <trace/define_trace.h>
++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) */
--- a/net/mac80211/iface.c 2009-07-08 15:46:16.452255410 -0700
+++ b/net/mac80211/iface.c 2009-07-08 15:46:06.060257895 -0700
@@ -643,6 +643,7 @@
--
1.6.2.1
^ permalink raw reply related
* [PATCH 2/2] [compat-2.6] Fixes kernel panic with kernel 2.6.28 while scanning.
From: Hauke Mehrtens @ 2009-07-12 11:26 UTC (permalink / raw)
To: lrodriguez; +Cc: linux-wireless, Hauke Mehrtens
In-Reply-To: <1247397966-1374-1-git-send-email-hauke@hauke-m.de>
This Problem was introduced with 50334349aa7f6fba1002739bf08481fcf1fb0761
The Patch is based on http://osdir.com/ml/linux-wireless/2009-04/msg01085.html
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
compat/compat.diff | 72 +++++++++------------------------------------------
1 files changed, 13 insertions(+), 59 deletions(-)
diff --git a/compat/compat.diff b/compat/compat.diff
index 6214f4a..9b73788 100644
--- a/compat/compat.diff
+++ b/compat/compat.diff
@@ -817,66 +817,20 @@
#include <linux/workqueue.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
-@@ -113,7 +117,9 @@
- unsigned long ts;
- struct kref ref;
- atomic_t hold;
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
- bool ies_allocated;
-+#endif
-
- /* must be last because of priv member */
- struct cfg80211_bss pub;
---- a/net/wireless/scan.c 2009-07-07 13:34:00.746682337 -0700
-+++ b/net/wireless/scan.c 2009-07-07 13:34:01.727705768 -0700
-@@ -88,10 +88,12 @@
- bss = container_of(ref, struct cfg80211_internal_bss, ref);
- if (bss->pub.free_priv)
- bss->pub.free_priv(&bss->pub);
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
-
- if (bss->ies_allocated)
- kfree(bss->pub.information_elements);
-
-+#endif
- BUG_ON(atomic_read(&bss->hold));
-
- kfree(bss);
-@@ -397,12 +399,25 @@
-
- found = rb_find_bss(dev, res);
-
-- if (found) {
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
-+ if (found) {
-+#else
-+ if (found && overwrite) {
-+ list_replace(&found->list, &res->list);
-+ rb_replace_node(&found->rbn, &res->rbn,
-+ &dev->bss_tree);
-+ /* XXX: workaround */
-+ res->hold = found->hold;
-+ kref_put(&found->ref, bss_release);
-+ found = res;
-+ } else if (found) {
-+#endif
- found->pub.beacon_interval = res->pub.beacon_interval;
- found->pub.tsf = res->pub.tsf;
- found->pub.signal = res->pub.signal;
- found->pub.capability = res->pub.capability;
- found->ts = res->ts;
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
-
- /* overwrite IEs */
- if (overwrite) {
-@@ -430,6 +445,7 @@
- }
- }
-
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -409,7 +409,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
+ size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
+ size_t ielen = res->pub.len_information_elements;
+
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
++ if (0) {
++#else
+ if (!found->ies_allocated && ksize(found) >= used + ielen) {
+#endif
- kref_put(&res->ref, bss_release);
- } else {
- /* this "consumes" the reference */
+ memcpy(found->pub.information_elements,
+ res->pub.information_elements, ielen);
+ found->pub.len_information_elements = ielen;
--- a/drivers/net/wireless/Makefile 2009-07-06 12:53:07.479194884 -0700
+++ b/drivers/net/wireless/Makefile 2009-07-06 12:54:42.026195576 -0700
@@ -5,43 +5,16 @@
--
1.6.2.1
^ permalink raw reply related
* Re: ath5k and Atheros AR242x - No scan results
From: Joel Roth @ 2009-07-12 11:23 UTC (permalink / raw)
To: Joel Roth; +Cc: linux-wireless
In-Reply-To: <20090630170916.GB5137@sprite>
On Tue, Jun 30, 2009 at 07:09:16AM -1000, Joel Roth wrote:
> Hello all,
>
> I'd appreciate some help troubleshooting my wireless connection.
>
> I have a Toshiba Satellite L305 series laptop running Debian
> sid with a recent, stock Debian kernel version 2.6.29-2-486.
>
> $ lspci | grep Atheros
>
> 05:00.0 Ethernet controller: Atheros Communications Inc. AR242x 802.11abg Wireless PCI Express Adapter (rev 01)
>
> I am seeking to connect to a D-Link 614+ wireless router.
> For initial testing, the AP is unencrypted, unsecured.
>
> My wife's G3 i-Book with AfterTheMac USB wireless adapter
> connected just fine, on the first try.
>
> I believe I have the modules I should have:
>
> $ lsmod | grep 80211
> mac80211 139680 1 ath5k
> cfg80211 21576 2 ath5k,mac80211
>
> My wireless network interface is present:
>
> $ iwconfig wlan0
>
> wlan0 IEEE 802.11 ESSID:""
> Mode:Managed Frequency:2.412 GHz Access Point: Not-Associated
> Tx-Power=0 dBm
> Retry min limit:7 RTS thr:off Fragment thr=2352 B
> Link Quality:0 Signal level:0 Noise level:0
> Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
> Tx excessive retries:0 Invalid misc:0 Missed beacon:0
>
> $ ifconfig wlan0
>
> wlan0 Link encap:Ethernet HWaddr 00:21:63:82:82:40
> UP BROADCAST MULTICAST MTU:1500 Metric:1
> RX packets:0 errors:0 dropped:0 overruns:0 frame:0
> TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
> collisions:0 txqueuelen:1000
> RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
>
>
> However, I don't find the D-Link 614+:
>
> $ iwlist wlan0 scan
>
> wlan0 No scan results
>
> And of course, dhclient fails to find a server.
>
> Am I missing something? What could I try next?
> I'd appreciate any pointers.
>
> Thanks.
Okay, I'm back with a new kernel 2.6.30.1 and the latest
ath5k. Here are my basic diagnostics data.
$ iwlist wlan0 scan
wlan0 No scan results
$ iwlist wlan0 ap
wlan0 Interface doesn't have a list of Peers/Access-Points
$ iwconfig wlan0
wlan0 IEEE 802.11bg ESSID:""
Mode:Managed Frequency:2.412 GHz Access Point: Not-Associated
Tx-Power=27 dBm
Retry min limit:7 RTS thr:off Fragment thr:off
Power Management:off
Link Quality:0 Signal level:0 Noise level:0
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
$ ifconfig wlan0
wlan0 Link encap:Ethernet HWaddr 00:21:63:82:82:40
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
dmesg highlights
[ 4.884157] ath5k 0000:05:00.0: enabling device (0000 -> 0002)
[ 4.884223] ath5k 0000:05:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
[ 4.884283] ath5k 0000:05:00.0: setting latency timer to 64
[ 4.884326] ath5k 0000:05:00.0: registered as 'phy0'
[ 6.411392] ath5k phy0: Atheros AR2425 chip found (MAC: 0xe2, PHY: 0x70)
[ 337.543014] ADDRCONF(NETDEV_UP): wlan0: link is not ready
I compiled the kernel with debugfs support for wireless. Can someone
point me to helpful docs in setting this up.
Also, is there a chance that another driver would serve me better?
Regards,
--
Joel Roth
^ permalink raw reply
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Johannes Berg @ 2009-07-12 9:38 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linux-wireless
In-Reply-To: <m2y6qukjqa.fsf@igel.home>
[-- Attachment #1: Type: text/plain, Size: 501 bytes --]
On Sat, 2009-07-11 at 23:11 +0200, Andreas Schwab wrote:
> Johannes Berg <johannes@sipsolutions.net> writes:
>
> > Odd, do you get console output before it hangs so you could add printks
> > to figure out where? Jan said that just fixed it for him.
>
> Just to clarify, the hanging resume is a different bug. When applying
> the patch on top of 5bb644a0f both suspend and resume work.
Alright, thanks, that's good to know. I'll submit a fix for this issue
tomorrow, I hope.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH] cfg80211: fix disabling WPA via wext (SIOCSIWAUTH)
From: Gábor Stefanik @ 2009-07-12 0:03 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Johannes Berg, Gábor Stefanik
cfg80211_set_wpa_version completely missed the use case when disabling
WPA, considering IW_AUTH_WPA_VERSION_DISABLED an invalid argument. This
caused weird error messages in wpa_supplicant.
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
---
net/wireless/wext-compat.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index aa80c0c..e6731bf 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -880,9 +880,19 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
wdev->wext.connect.crypto.wpa_versions = 0;
if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
- IW_AUTH_WPA_VERSION_WPA2))
+ IW_AUTH_WPA_VERSION_WPA2|
+ IW_AUTH_WPA_VERSION_DISABLED))
return -EINVAL;
+ if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
+ (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
+ IW_AUTH_WPA_VERSION_WPA2)))
+ return -EINVAL;
+
+ if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
+ wdev->wext.connect.crypto.wpa_versions &=
+ ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+
if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
wdev->wext.connect.crypto.wpa_versions |=
NL80211_WPA_VERSION_1;
--
1.5.4.5
^ permalink raw reply related
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Andreas Schwab @ 2009-07-11 21:11 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1247345548.30647.116.camel@johannes.local>
Johannes Berg <johannes@sipsolutions.net> writes:
> Odd, do you get console output before it hangs so you could add printks
> to figure out where? Jan said that just fixed it for him.
Just to clarify, the hanging resume is a different bug. When applying
the patch on top of 5bb644a0f both suspend and resume work.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [Orinoco-devel] orinoco-usb in 2.6.31?
From: Dave @ 2009-07-11 20:55 UTC (permalink / raw)
To: orinoco-devel; +Cc: David Gerard, linux-wireless
In-Reply-To: <4A57DC26.4090708@gmail.com>
Dave wrote:
> Dave wrote:
>> David Gerard wrote:
>>> I'm trying to get the infamous Compaq W200 wifi adapter working in
>>> Ubuntu Karmic Koala (9.10), which uses kernel 2.6.31. Unfortunately,
>>> the latest version of orinoco_usb (svn rev 1300) doesn't compile with
>>> this kernel, even with the patch that got the driver working in
>>> 2.6.27/28 (Ubuntu 8.10/9.04).
>
> I've set up a git repo* containing the recent usb patches, and dropped
> some simple history into it. At some point I'll see if I can rebase the
> usb branch to recent mainline.
>
> * <http://repo.or.cz/w/orinoco_usb.git>
The rebasing was a little painful due to all the changes that have been
happening on orinoco. However I think I'm done.
What can you do? If you have one of these USB sticks and a kernel after
.27, please test (because I can't). Testing with 2.6.30 is most useful,
but I'll be happy with anything.
Kernel Please test baseline
v2.6.27 usb-no-wpa-v2.6.27
v2.6.28 usb-no-move-v2.6.28
v2.6.29 usb-no-refactor-v2.6.29
v2.6.30 usb-no-cfg80211-v2.6.30
v2.6.31-rc usb-no-cfg80211-v2.6.30
If the above baseline doesn't work for you, it's possible that there's
another baseline you can try - see below for a description of what's in
the repo.
At the very bottom of this email there's a quick note on building the
driver.
I'll try to update this repo for the next few kernel releases. But
hopefully I can have look at merging this to mainline after orinocos
cfg80211 support is done.
Enjoy,
Dave.
---
What's in the repository?
The master branch in the above repository is unchanged - it holds the
sources from svn based on 2.6.18 with build fixes for later kernels.
There are 4 other branches based off of 2.6.27/28/29/30 which have
rebased versions of the driver from master, broken down into the primary
conceptual changes. The branches are the version numbers with a -usb
suffix. If you need the firmware tools, stick with master.
At the end of each branch I've included the build fixes that allow the
branch to build with a more recent kernel.
Basically you want to try the branch for your kernel first. If it
doesn't work, go back to the previous branch. On a given branch use the
latest baseline with a lower (or equal) kernel version in the baseline name.
v2.6.27 is the last release before things really started changing. This
branch has the best chance of working, and just ensures we've picked up
all the fixes that have come in. It does include a change in scanning
which might break USB.
v2.6.28 introduced firmware download and WPA on the Agere devices. I've
explicitly disabled firmware download for the Agere USB devices -
someones going to have to figure out how to actually do that. If you
happen to have a 9.42 Agere firmware on your USB stick the driver will
attempt to do WPAish things. This is highly unlikely to work, but I
don't expect any sticks to have that firmware.
v2.6.29 didn't contain too many functional changes from .28. I think
there might be an oops fix. However code moved directories here, so it
made sense to rebase on top of this release.
v2.6.30 contained a refactorring of orinoco.c. A lot of the merging had
to be done manually here, so it's possible I've broken something.
---
Some notes on building:
If you're building from master, build from the directory containing the
source:
cd drivers/net/wireless
make KERNEL_PATH=xxx
On the branches I've kept the makefiles in that directory exactly the
same as mainline, so build at the root of the tree.
cd drivers/net/wireless/../../..
make KERNEL_PATH=xxx
^ permalink raw reply
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Johannes Berg @ 2009-07-11 20:52 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linux-wireless
In-Reply-To: <m2ab3bkm2d.fsf@igel.home>
[-- Attachment #1: Type: text/plain, Size: 907 bytes --]
On Sat, 2009-07-11 at 22:21 +0200, Andreas Schwab wrote:
> Johannes Berg <johannes@sipsolutions.net> writes:
>
> > On Sat, 2009-07-11 at 18:02 +0200, Andreas Schwab wrote:
> >>
> >> Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> writes:
> >>
> >> > We forgot to cancel all timers in mac80211 when suspending.
> >> > In particular we forgot to deal with some things that can
> >> > cause hardware reconfiguration -- while it is down.
> >>
> >> This is breaking suspend on my iBook.
> >
> > Yeah, bug 13337,
>
> Thanks, I missed that one.
>
> > but the fix at
> > http://mid.gmane.org/8763dznnki.fsf@scholz.fias.uni-frankfurt.de works.
>
> With that patch suspend works here too, but resume hangs halfway
> through.
Odd, do you get console output before it hangs so you could add printks
to figure out where? Jan said that just fixed it for him.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Andreas Schwab @ 2009-07-11 20:21 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1247334562.30647.111.camel@johannes.local>
Johannes Berg <johannes@sipsolutions.net> writes:
> On Sat, 2009-07-11 at 18:02 +0200, Andreas Schwab wrote:
>>
>> Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> writes:
>>
>> > We forgot to cancel all timers in mac80211 when suspending.
>> > In particular we forgot to deal with some things that can
>> > cause hardware reconfiguration -- while it is down.
>>
>> This is breaking suspend on my iBook.
>
> Yeah, bug 13337,
Thanks, I missed that one.
> but the fix at
> http://mid.gmane.org/8763dznnki.fsf@scholz.fias.uni-frankfurt.de works.
With that patch suspend works here too, but resume hangs halfway
through.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH] ath9k: Fix enabling OFDM weak signal detection
From: Steven Luo @ 2009-07-11 18:48 UTC (permalink / raw)
To: Nick Kossifidis
Cc: John W. Linville, Luis R. Rodriguez, Jouni Malinen,
Sujith Manoharan, Vasanthakumar Thiagarajan,
Senthil Balasubramanian, linux-wireless, ath9k-devel
In-Reply-To: <40f31dec0907110826o75f73dbfw2aed84304feff264@mail.gmail.com>
On Sat, Jul 11, 2009 at 06:26:14PM +0300, Nick Kossifidis wrote:
> Does your AP operate on 2.4GHz band or 5GHz ?
2.4 GHz -- my card doesn't support 5 GHz operation.
-Steven Luo
^ permalink raw reply
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Johannes Berg @ 2009-07-11 17:49 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linux-wireless
In-Reply-To: <m2hbxjky1q.fsf@igel.home>
[-- Attachment #1: Type: text/plain, Size: 583 bytes --]
On Sat, 2009-07-11 at 18:02 +0200, Andreas Schwab wrote:
>
> Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> writes:
>
> > We forgot to cancel all timers in mac80211 when suspending.
> > In particular we forgot to deal with some things that can
> > cause hardware reconfiguration -- while it is down.
>
> This is breaking suspend on my iBook.
Yeah, bug 13337, we've figured out why too, I need two or three days to
figure out whether it's race-free, but the fix at
http://mid.gmane.org/8763dznnki.fsf@scholz.fias.uni-frankfurt.de works.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: ath5k AP support?
From: Tomasz Chmielewski @ 2009-07-11 16:20 UTC (permalink / raw)
To: Bob Copeland; +Cc: linux-wireless
In-Reply-To: <20090705120228.GD2132@hash.localnet>
Bob Copeland wrote:
> On Thu, Jun 18, 2009 at 10:22:36PM +0200, Tomasz Chmielewski wrote:
>> Oh well.
>> The above is with hostapd 0.7.0 snapshot.
>> With 0.6.9 I can connect and the connection works fine
>>
>> Is it normal?
>
> I'm not sure -- do you have anything in dmesg?
>
> I've noticed a strange bug lately where some packets to the STA get dropped
> due to some kind of off-by-u32 bug. I haven't tracked it down yet to
> any certain combination of ath5k/w-t/hostapd, though.
No, nothing in dmesg.
I checked out 0.7 now, and it seems to work.
So, problem solved.
--
Tomasz Chmielewski
http://wpkg.org
^ permalink raw reply
* [PATCH] rt2x00: Remove DEVICE_STATE_DISABLED_RADIO_HW
From: Ivo van Doorn @ 2009-07-11 16:00 UTC (permalink / raw)
To: John Linville; +Cc: users, linux-wireless
The DEVICE_STATE_DISABLED_RADIO_HW flag is only read but never set,
it is an ancient part of one of the many versions of the rfkill implementations
in rt2x00. It is about time is disappears.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index de3f13a..a111b04 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -600,7 +600,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 4fff3a8..658a63b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
/*
^ permalink raw reply related
* Re: [PATCH v2] mac80211: cancel/restart all timers across suspend/resume
From: Andreas Schwab @ 2009-07-11 16:02 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, linux-wireless, Luis R. Rodriguez
In-Reply-To: <1242553242.10005.76.camel@johannes.local>
Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> writes:
> We forgot to cancel all timers in mac80211 when suspending.
> In particular we forgot to deal with some things that can
> cause hardware reconfiguration -- while it is down.
This is breaking suspend on my iBook.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH] ath9k: Fix enabling OFDM weak signal detection
From: Nick Kossifidis @ 2009-07-11 15:26 UTC (permalink / raw)
To: Steven Luo
Cc: John W. Linville, Luis R. Rodriguez, Jouni Malinen,
Sujith Manoharan, Vasanthakumar Thiagarajan,
Senthil Balasubramanian, linux-wireless, ath9k-devel
In-Reply-To: <20090709211221.GA4854@steven676.net>
2009/7/10 Steven Luo <steven@steven676.net>:
> From: Steven Luo <steven@steven676.net>
>
> It seems that OFDM weak signal detection should be enabled after an ANI
> state reset, as indicated by the initial setting of ofdmWeakSigDetectOff
> and what the open Atheros HAL does. Unfortunately, the reversed sense
> of ofdmWeakSigDetectOff (true if weak signal detection is NOT enabled)
> seems to have resulted in a mixup here, causing weak signal detection to
> be disabled.
>
> This patch significantly improves reception and throughput from distant
> stations for my AR5416-based AP running compat-wireless 2009-06-25.
>
(sorry, bad reply to all)
Does your AP operate on 2.4GHz band or 5GHz ?
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* [PATCH] ar9170: implement transmit aggregation
From: Christian Lamparter @ 2009-07-11 15:24 UTC (permalink / raw)
To: wireless; +Cc: John W. Linville
This patch roughly implements xmit aggregation for ar9170-like device.
Not all AP are compatible with the driver(and firmware) yet, so YMMV.
A more refined code will definitely need the final HT specification
to be available for the public, lots of firmware modification and
possibly a redesigned driver just for good measure.
Sadly, these conditions won't come true anytime soon...
Signed-off-by: Christian Lamparter <chunkeey@web.de>
---
This changes have been sitting in the box long enough without
any complains... time to move on!
---
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index bb97981..e6c3ee3 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_NUM_MAX_BA_RETRY 5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum ar9170_tid_state {
+ AR9170_TID_STATE_INVALID,
+ AR9170_TID_STATE_SHUTDOWN,
+ AR9170_TID_STATE_PROGRESS,
+ AR9170_TID_STATE_COMPLETE,
+};
+
+struct ar9170_sta_tid {
+ struct list_head list;
+ struct sk_buff_head queue;
+ u8 addr[ETH_ALEN];
+ u16 ssn;
+ u16 tid;
+ enum ar9170_tid_state state;
+ bool active;
+ u8 retry;
+};
+
#define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8
+#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff
+#define AR9170_NUM_TX_STATUS 128
+#define AR9170_NUM_TX_AGG_MAX 30
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
@@ -187,14 +228,25 @@ struct ar9170 {
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor;
+ /* tx ampdu */
+ struct sk_buff_head tx_status_ampdu;
+ spinlock_t tx_ampdu_list_lock;
+ struct list_head tx_ampdu_list;
+ unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
+
+ /* (cached) HW A-MPDU settings */
+ u8 global_ampdu_density;
+ u8 global_ampdu_factor;
};
struct ar9170_sta_info {
+ struct ar9170_sta_tid agg[AR9170_NUM_TID];
+ unsigned int ampdu_max_len;
};
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 51753ed..c298529 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_ht;
+module_param_named(ht, modparam_ht, bool, S_IRUGO);
+MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
+
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
- .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
+#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb)))
+
+#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags,
+ ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
+#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue)
{
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags);
}
+#endif /* AR9170_QUEUE_DEBUG */
+#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
- wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
- ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+ " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+ ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
+#endif /* AR9170_QUEUE_STOP_DEBUG */
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{
unsigned long flags;
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- __ar9170_dump_txstats(ar);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+ spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
+ printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
+ spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
}
-#endif /* AR9170_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
+static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
+{
+ struct sk_buff_head success;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned long queue_bitmap = 0;
+
+ skb_queue_head_init(&success);
+
+ while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
+ __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
+
+ ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
+ wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
+ __ar9170_dump_txqueue(ar, &success);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = __skb_dequeue(&success))) {
+ struct ieee80211_tx_info *txinfo;
+
+ queue_bitmap |= BIT(skb_get_queue_mapping(skb));
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ txinfo->flags |= IEEE80211_TX_STAT_ACK;
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ }
+
+ for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+ ieee80211_wake_queue(ar->hw, i);
+ }
+
+ if (queue_bitmap)
+ ar9170_tx(ar);
+}
+
+static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_BA_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status_ampdu, skb);
+ ar9170_tx_fake_ampdu_status(ar);
+ ar->tx_ampdu_pending--;
+
+ if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
+}
+
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- dev_kfree_skb_any(skb);
+ ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL;
}
+static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+
+ while (count) {
+ skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
+ if (!skb)
+ break;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ /* FIXME: maybe more ? */
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ count--;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ if (count) {
+ printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
+ "suitable frames left in tx_status queue.\n",
+ wiphy_name(ar->hw->wiphy), count);
+
+ ar9170_dump_tx_status_ampdu(ar);
+ }
+#endif /* AR9170_TXAGG_DEBUG */
+}
+
/*
* This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are
@@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
+ ar9170_tx_fake_ampdu_status(ar);
+
if (resched)
queue_delayed_work(ar->hw->workqueue,
&ar->tx_janitor,
@@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case 0xc4:
+ /* BlockACK bitmap */
+ break;
+
case 0xc5:
/* BlockACK events */
+ ar9170_handle_block_ack(ar,
+ le16_to_cpu(cmd->ba_fail_cnt.failed),
+ le16_to_cpu(cmd->ba_fail_cnt.rate));
+ ar9170_tx_fake_ampdu_status(ar);
break;
case 0xc6:
@@ -1098,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ /* set sane AMPDU defaults */
+ ar->global_ampdu_density = 6;
+ ar->global_ampdu_factor = 3;
+
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1143,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor);
+ cancel_delayed_work_sync(&ar->led_work);
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex);
@@ -1159,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]);
}
+ skb_queue_purge(&ar->tx_status_ampdu);
+
mutex_unlock(&ar->mutex);
}
+static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
+}
+
+static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
+ struct sk_buff *src)
+{
+ struct ar9170_tx_control *dst_txc, *src_txc;
+ struct ieee80211_tx_info *dst_info, *src_info;
+ struct ar9170_tx_info *dst_arinfo, *src_arinfo;
+
+ src_txc = (void *) src->data;
+ src_info = IEEE80211_SKB_CB(src);
+ src_arinfo = (void *) src_info->rate_driver_data;
+
+ dst_txc = (void *) dst->data;
+ dst_info = IEEE80211_SKB_CB(dst);
+ dst_arinfo = (void *) dst_info->rate_driver_data;
+
+ dst_txc->phy_control = src_txc->phy_control;
+
+ /* same MCS for the whole aggregate */
+ memcpy(dst_info->driver_rates, src_info->driver_rates,
+ sizeof(dst_info->driver_rates));
+}
+
static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -1230,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
goto out;
}
@@ -1360,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
}
+static bool ar9170_tx_ampdu(struct ar9170 *ar)
+{
+ struct sk_buff_head agg;
+ struct ar9170_sta_tid *tid_info = NULL, *tmp;
+ struct sk_buff *skb, *first = NULL;
+ unsigned long flags, f2;
+ unsigned int i = 0;
+ u16 seq, queue, tmpssn;
+ bool run = false;
+
+ skb_queue_head_init(&agg);
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (list_empty(&ar->tx_ampdu_list)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: aggregation list is empty.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ goto out_unlock;
+ }
+
+ list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
+ if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ if (++i > 64) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: enough frames aggregated.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ break;
+ }
+
+ queue = TID_TO_WME_AC(tid_info->tid);
+
+ if (skb_queue_len(&ar->tx_pending[queue]) >=
+ AR9170_NUM_TX_AGG_MAX) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queue %d full.\n",
+ wiphy_name(ar->hw->wiphy), queue);
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ list_del_init(&tid_info->list);
+
+ spin_lock_irqsave(&tid_info->queue.lock, f2);
+ tmpssn = seq = tid_info->ssn;
+ first = skb_peek(&tid_info->queue);
+
+ if (likely(first))
+ tmpssn = ar9170_get_seq(first);
+
+ if (unlikely(tmpssn != seq)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
+ wiphy_name(ar->hw->wiphy), seq, tmpssn);
+#endif /* AR9170_TXAGG_DEBUG */
+ tid_info->ssn = tmpssn;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
+ "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid, tid_info->ssn,
+ skb_queue_len(&tid_info->queue));
+ __ar9170_dump_txqueue(ar, &tid_info->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = skb_peek(&tid_info->queue))) {
+ if (unlikely(ar9170_get_seq(skb) != seq))
+ break;
+
+ __skb_unlink(skb, &tid_info->queue);
+ tid_info->ssn = seq = GET_NEXT_SEQ(seq);
+
+ if (unlikely(skb_get_queue_mapping(skb) != queue)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
+ "!match.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid,
+ TID_TO_WME_AC(tid_info->tid),
+ skb_get_queue_mapping(skb));
+#endif /* AR9170_TXAGG_DEBUG */
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (unlikely(first == skb)) {
+ ar9170_tx_prepare_phy(ar, skb);
+ __skb_queue_tail(&agg, skb);
+ first = skb;
+ } else {
+ ar9170_tx_copy_phy(ar, skb, first);
+ __skb_queue_tail(&agg, skb);
+ }
+
+ if (unlikely(skb_queue_len(&agg) ==
+ AR9170_NUM_TX_AGG_MAX))
+ break;
+ }
+
+ if (skb_queue_empty(&tid_info->queue))
+ tid_info->active = false;
+ else
+ list_add_tail(&tid_info->list,
+ &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&tid_info->queue.lock, f2);
+
+ if (unlikely(skb_queue_empty(&agg))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queued empty list!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ /*
+ * tell the FW/HW that this is the last frame,
+ * that way it will wait for the immediate block ack.
+ */
+ if (likely(skb_peek_tail(&agg)))
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &agg);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+
+ spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
+ skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+ spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
+ run = true;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ __skb_queue_purge(&agg);
+
+ return run;
+}
+
static void ar9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1384,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
- printk(KERN_DEBUG "stuck frames: ===> \n");
+ printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+ wiphy_name(ar->hw->wiphy));
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: stop queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue;
@@ -1403,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space,
frames);
-
- ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1432,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending++;
+
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1440,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending--;
+
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1461,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed =>\n",
+ printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
}
@@ -1479,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
+static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct ar9170_sta_info *sta_info;
+ struct ar9170_sta_tid *agg;
+ struct sk_buff *iter;
+ unsigned long flags, f2;
+ unsigned int max;
+ u16 tid, seq, qseq;
+ bool run = false, queue = false;
+
+ tid = ar9170_get_tid(skb);
+ seq = ar9170_get_seq(skb);
+ txinfo = IEEE80211_SKB_CB(skb);
+ sta_info = (void *) txinfo->control.sta->drv_priv;
+ agg = &sta_info->agg[tid];
+ max = sta_info->ampdu_max_len;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+
+ if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
+ "for ESS:%pM tid:%d state:%d.\n",
+ wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
+ agg->state);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ if (!agg->active) {
+ agg->active = true;
+ agg->ssn = seq;
+ queue = true;
+ }
+
+ /* check if seq is within the BA window */
+ if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
+ "fit into BA window (%d - %d)\n",
+ wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
+ (agg->ssn + max) & 0xfff);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ spin_lock_irqsave(&agg->queue.lock, f2);
+
+ skb_queue_reverse_walk(&agg->queue, iter) {
+ qseq = ar9170_get_seq(iter);
+
+ if (GET_NEXT_SEQ(qseq) == seq) {
+ __skb_queue_after(&agg->queue, iter, skb);
+ goto queued;
+ }
+ }
+
+ __skb_queue_head(&agg->queue, skb);
+
+queued:
+ spin_unlock_irqrestore(&agg->queue.lock, f2);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
+ wiphy_name(ar->hw->wiphy), skb);
+ __ar9170_dump_txqueue(ar, &agg->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
+ run = true;
+
+ if (queue)
+ list_add_tail(&agg->list, &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ return run;
+
+err_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ dev_kfree_skb_irq(skb);
+ return false;
+}
+
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ar9170 *ar = hw->priv;
@@ -1492,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- /* drop frame, we do not allow TX A-MPDU aggregation yet. */
- goto err_free;
+ bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+ if (run || !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1931,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ memset(sta_info, 0, sizeof(*sta_info));
+
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+ ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+
+ if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+ ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+ sta_info->agg[i].active = false;
+ sta_info->agg[i].ssn = 0;
+ sta_info->agg[i].retry = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ break;
+
+ case STA_NOTIFY_REMOVE:
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+ skb_queue_purge(&sta_info->agg[i].queue);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (IS_STARTED(ar) && ar->filter_changed)
+ queue_work(ar->hw->workqueue, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1985,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
+ unsigned long flags;
+
+ if (!modparam_ht)
+ return -EOPNOTSUPP;
+
switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
+ !list_empty(&tid_info->list)) {
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
+ "is in a very bad state!\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ return -EBUSY;
+ }
+
+ *ssn = tid_info->ssn;
+ tid_info->state = AR9170_TID_STATE_PROGRESS;
+ tid_info->active = false;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ tid_info->state = AR9170_TID_STATE_SHUTDOWN;
+ list_del_init(&tid_info->list);
+ tid_info->active = false;
+ skb_queue_purge(&tid_info->queue);
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ break;
+
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- /*
- * Something goes wrong -- RX locks up
- * after a while of receiving aggregated
- * frames -- not enabling for now.
- */
- return -EOPNOTSUPP;
+ /* Handled by firmware */
+ break;
+
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static const struct ieee80211_ops ar9170_ops = {
@@ -2045,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
+ spin_lock_init(&ar->tx_ampdu_list_lock);
+ skb_queue_head_init(&ar->tx_status_ampdu);
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]);
@@ -2053,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size)
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
+ INIT_LIST_HEAD(&ar->tx_ampdu_list);
/* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0];
@@ -2066,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
+ if (modparam_ht) {
+ ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ } else {
+ ar9170_band_2GHz.ht_cap.ht_supported = false;
+ ar9170_band_5GHz.ht_cap.ht_supported = false;
+ }
+
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2091,6 +2632,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW];
+ unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2127,6 +2669,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++;
}
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams)
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
^ permalink raw reply related
* Re: [ath9k-devel] [PATCH] ath9k: Fix enabling OFDM weak signal detection
From: Nick Kossifidis @ 2009-07-11 15:23 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Steven Luo, Bennyam Malavazi, John W. Linville, linux-wireless,
Jouni Malinen, Senthil Balasubramanian, ath9k-devel,
Vasanthakumar Thiagarajan
In-Reply-To: <43e72e890907101102i29352c6bq9e511663e2c3a986@mail.gmail.com>
2009/7/10 Luis R. Rodriguez <mcgrof@gmail.com>:
> On Thu, Jul 9, 2009 at 2:12 PM, Steven Luo<steven@steven676.net> wrote:
>> From: Steven Luo <steven@steven676.net>
>>
>> It seems that OFDM weak signal detection should be enabled after an ANI
>> state reset, as indicated by the initial setting of ofdmWeakSigDetectOff
>> and what the open Atheros HAL does. Unfortunately, the reversed sense
>> of ofdmWeakSigDetectOff (true if weak signal detection is NOT enabled)
>> seems to have resulted in a mixup here, causing weak signal detection to
>> be disabled.
>>
>> This patch significantly improves reception and throughput from distant
>> stations for my AR5416-based AP running compat-wireless 2009-06-25.
>>
>> Signed-off-by: Steven Luo <steven@steven676.net>
>> Cc: stable@kernel.org
>> ---
>
> NACK for now, please give us a chance to review this -- this may
> actually be correct.
>
> Luis
>
>> --- a/drivers/net/wireless/ath/ath9k/ani.c 2009-06-24 21:14:00.000000000 -0700
>> +++ b/drivers/net/wireless/ath/ath9k/ani.c 2009-07-06 02:45:57.000000000 -0700
>> @@ -482,7 +482,7 @@ void ath9k_ani_reset(struct ath_hw *ah)
>> ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
>> ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
>> ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
>> - !ATH9K_ANI_USE_OFDM_WEAK_SIG);
>> + ATH9K_ANI_USE_OFDM_WEAK_SIG);
>> ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
>> ATH9K_ANI_CCK_WEAK_SIG_THR);
>>
>>
Does your AP operate on 2.4GHz band or 5GHz ?
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* Re: [PATCH] wireless: fix supported cards for rtl8187
From: Hin-Tak Leung @ 2009-07-11 4:33 UTC (permalink / raw)
To: Marcin Slusarz
Cc: Larry Finger, John W. Linville, Linux wireless,
Przemyslaw Kulczycki, LKML, Gábor Stefanik
In-Reply-To: <4A55EC95.5000309@gmail.com>
2009/7/9 Marcin Slusarz <marcin.slusarz@gmail.com>:
> Look, support for Ralink chipsets is a mess. They are supported by too sets
> of drivers - Ralink's ugly as hell but working staging drivers (rt2860,
> rt2870, rt3070, soon rt3090) and properly developed but lagging rt2x00
> drivers (RT2400PCI, RT2500PCI, RT61PCI, RT2500USB, RT73USB, RT2800USB).
>
> Theoretically my WUSB54GCv3 is supported by RT2800USB (which was added during
> 2.6.31 merge window), but it doesn't work. With tiny patch added to rt3070
> (just usb id) my card works. Some day rt2x00 drivers will be better than Ralink's,
> but right now they are not.
>
> So I wouldn't like to encourage any of them. I just wanted to fix clearly
> wrong help text which stated that rtl8187 (Realtek's chipset!) supports
> all WUSB54GC cards.
I think you mis-read the Kconfig message. GPL clause 11:
...PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE...
The linux kernel never claim to cover *all* of anything, and in
particular, the message you refers to is meant to read '*some*
WUSB54GC are known to work', YMMV. I think adding pointers/info to v1
and3 would be better if you want to add 'v2' to it; particularly since
Gabor has pointed out that v1/v2/v3 all have different USB ids and a
full set of kernel modules will bind to the different devices
correctly, so the message is only for people who has a new/unknown
device and want to experiment (and expect to have some failures). And
to be honest, there is a device called rtl8187se, which isn't an
rtl8187 at all and don't have much in common. If you start insisting
the rtl8187 Kconfig message should have an extra 5 letters say 'not
se', I would rather you say 'rtl8187se is covered by ..., which is in
staging phase'. (the se driver is, the last time I heard, in staging
and not working and nobody is working on it to make it work, which is
worse than your situation).
The situation with Ralink drivers isn't that different in other
vendors - Realtek provides a vendor driver for rtl8187 called "r8187"
and there is a community driver rtl8187; Atheros provides a vendor
driver for Zydas zd1211 and there is a community driver zd1211rw. I
don't think this "wouldn't like to encourage any of them" attitude is
helping anybody. In both of the Realtek case and the Zydas case,
people tolerated the co-existences of both (and sometimes with
ndiswrapper also) for many months and studied the vendor drivers (+
ndiswrapper) and eventually improve the community driver.
Driver codes don't grow on trees - if you 'wouldn't like to encourage
any of them', maybe you should not be using linux at all.
^ permalink raw reply
* Re: [PATCH 2.6.31] rfkill: allow toggling soft state in sysfs again
From: Darren Salt @ 2009-07-10 23:09 UTC (permalink / raw)
To: Johannes Berg
Cc: John Linville, Thiemo Nagel, Corentin Chary, debian-eeepc-devel,
acpi4asus-user, linux-wireless, linux-kernel
In-Reply-To: <1247262952.26071.1.camel@johannes.local>
I demand that Johannes Berg may or may not have written...
> On Fri, 2009-07-10 at 22:09 +0100, Darren Salt wrote:
>> I demand that Johannes Berg may or may not have written...
[snip]
>>> *shrug*, I don't like it, but whatever...
>> I do. It means that we have a nice simple text-based interface for use in
>> scripts (for now), and a binary interface which is better suited to the
>> likes of desktop applications.
> Indeed, and as long as you expect to only use soft toggle... problem is
> that you won't know whether it's soft-toggled or not while it's
> hard-blocked (off)!
Which is fine for eeepc-acpi-scripts and anything else which doesn't care
about hard-blocking because the hardware doesn't do that.
eeepc-acpi-scripts should eventually use your rfkill utility, though. (I
intend to make sure that it does so.)
[snip]
--
| Darren Salt | linux at youmustbejoking | nr. Ashington, | Doon
| using Debian GNU/Linux | or ds ,demon,co,uk | Northumberland | Army
| Kill all extremists!
A large dog will have a surprising effect on your life.
^ permalink raw reply
* [PATCH] p54: generate channel list dynamically
From: Christian Lamparter @ 2009-07-10 23:22 UTC (permalink / raw)
To: wireless; +Cc: John W. Linville
This patch enhances the eeprom parser to generate customized
channel list for every device.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
---
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index a2a044e..549ef2d 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
+#include <linux/sort.h>
#include <net/mac80211.h>
@@ -41,30 +42,6 @@ static struct ieee80211_rate p54_bgrates[] = {
{ .bitrate = 540, .hw_value = 11, },
};
-static struct ieee80211_channel p54_bgchannels[] = {
- { .center_freq = 2412, .hw_value = 1, },
- { .center_freq = 2417, .hw_value = 2, },
- { .center_freq = 2422, .hw_value = 3, },
- { .center_freq = 2427, .hw_value = 4, },
- { .center_freq = 2432, .hw_value = 5, },
- { .center_freq = 2437, .hw_value = 6, },
- { .center_freq = 2442, .hw_value = 7, },
- { .center_freq = 2447, .hw_value = 8, },
- { .center_freq = 2452, .hw_value = 9, },
- { .center_freq = 2457, .hw_value = 10, },
- { .center_freq = 2462, .hw_value = 11, },
- { .center_freq = 2467, .hw_value = 12, },
- { .center_freq = 2472, .hw_value = 13, },
- { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
- .channels = p54_bgchannels,
- .n_channels = ARRAY_SIZE(p54_bgchannels),
- .bitrates = p54_bgrates,
- .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
static struct ieee80211_rate p54_arates[] = {
{ .bitrate = 60, .hw_value = 4, },
{ .bitrate = 90, .hw_value = 5, },
@@ -76,51 +53,257 @@ static struct ieee80211_rate p54_arates[] = {
{ .bitrate = 540, .hw_value = 11, },
};
-static struct ieee80211_channel p54_achannels[] = {
- { .center_freq = 4920 },
- { .center_freq = 4940 },
- { .center_freq = 4960 },
- { .center_freq = 4980 },
- { .center_freq = 5040 },
- { .center_freq = 5060 },
- { .center_freq = 5080 },
- { .center_freq = 5170 },
- { .center_freq = 5180 },
- { .center_freq = 5190 },
- { .center_freq = 5200 },
- { .center_freq = 5210 },
- { .center_freq = 5220 },
- { .center_freq = 5230 },
- { .center_freq = 5240 },
- { .center_freq = 5260 },
- { .center_freq = 5280 },
- { .center_freq = 5300 },
- { .center_freq = 5320 },
- { .center_freq = 5500 },
- { .center_freq = 5520 },
- { .center_freq = 5540 },
- { .center_freq = 5560 },
- { .center_freq = 5580 },
- { .center_freq = 5600 },
- { .center_freq = 5620 },
- { .center_freq = 5640 },
- { .center_freq = 5660 },
- { .center_freq = 5680 },
- { .center_freq = 5700 },
- { .center_freq = 5745 },
- { .center_freq = 5765 },
- { .center_freq = 5785 },
- { .center_freq = 5805 },
- { .center_freq = 5825 },
+#define CHAN_HAS_CAL BIT(0)
+#define CHAN_HAS_LIMIT BIT(1)
+#define CHAN_HAS_CURVE BIT(2)
+#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+ u16 freq;
+ u16 data;
+ int index;
+ enum ieee80211_band band;
};
-static struct ieee80211_supported_band band_5GHz = {
- .channels = p54_achannels,
- .n_channels = ARRAY_SIZE(p54_achannels),
- .bitrates = p54_arates,
- .n_bitrates = ARRAY_SIZE(p54_arates),
+struct p54_channel_list {
+ struct p54_channel_entry *channels;
+ size_t entries;
+ size_t max_entries;
+ size_t band_channel_num[IEEE80211_NUM_BANDS];
};
+static int p54_get_band_from_freq(u16 freq)
+{
+ /* FIXME: sync these values with the 802.11 spec */
+
+ if ((freq >= 2412) && (freq <= 2484))
+ return IEEE80211_BAND_2GHZ;
+
+ if ((freq >= 4920) && (freq <= 5825))
+ return IEEE80211_BAND_5GHZ;
+
+ return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+ const void *_b)
+{
+ const struct p54_channel_entry *a = _a;
+ const struct p54_channel_entry *b = _b;
+
+ return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+ struct ieee80211_supported_band *band_entry,
+ enum ieee80211_band band)
+{
+ /* TODO: generate rate array dynamically */
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ band_entry->bitrates = p54_bgrates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ band_entry->bitrates = p54_arates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+ struct p54_channel_list *list,
+ enum ieee80211_band band)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_supported_band *tmp, *old;
+ unsigned int i, j;
+ int ret = -ENOMEM;
+
+ if ((!list->entries) || (!list->band_channel_num[band]))
+ return 0;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ goto err_out;
+
+ tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+ list->band_channel_num[band], GFP_KERNEL);
+ if (!tmp->channels)
+ goto err_out;
+
+ ret = p54_fill_band_bitrates(dev, tmp, band);
+ if (ret)
+ goto err_out;
+
+ for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+ (i < list->entries); i++) {
+
+ if (list->channels[i].band != band)
+ continue;
+
+ if (list->channels[i].data != CHAN_HAS_ALL) {
+ printk(KERN_ERR "%s:%s%s%s is/are missing for "
+ "channel:%d [%d MHz].\n",
+ wiphy_name(dev->wiphy),
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
+ }
+
+ tmp->channels[j].band = list->channels[i].band;
+ tmp->channels[j].center_freq = list->channels[i].freq;
+ j++;
+ }
+
+ tmp->n_channels = list->band_channel_num[band];
+ old = priv->band_table[band];
+ priv->band_table[band] = tmp;
+ if (old) {
+ kfree(old->channels);
+ kfree(old);
+ }
+
+ return 0;
+
+err_out:
+ if (tmp) {
+ kfree(tmp->channels);
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
+{
+ int band, i;
+
+ /*
+ * usually all lists in the eeprom are mostly sorted.
+ * so it's very likely that the entry we are looking for
+ * is right at the end of the list
+ */
+ for (i = list->entries; i >= 0; i--) {
+ if (freq == list->channels[i].freq) {
+ list->channels[i].data |= data;
+ break;
+ }
+ }
+
+ if ((i < 0) && (list->entries < list->max_entries)) {
+ /* entry does not exist yet. Initialize a new one. */
+ band = p54_get_band_from_freq(freq);
+
+ /*
+ * filter out frequencies which don't belong into
+ * any supported band.
+ */
+ if (band < 0)
+ return ;
+
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ list->channels[i].freq = freq;
+ list->channels[i].data = data;
+ list->channels[i].band = band;
+ list->channels[i].index = ieee80211_frequency_to_channel(freq);
+ /* TODO: parse output_limit and fill max_power */
+ }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_channel_list *list;
+ unsigned int i, j, max_channel_num;
+ int ret = -ENOMEM;
+ u16 freq;
+
+ if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+ (priv->iq_autocal_len != priv->output_limit->entries))
+ printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+ "to use all channels with this device.\n",
+ wiphy_name(dev->wiphy));
+
+ max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+ priv->iq_autocal_len);
+ max_channel_num = max_t(unsigned int, max_channel_num,
+ priv->curve_data->entries);
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ goto free;
+
+ list->max_entries = max_channel_num;
+ list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+ max_channel_num, GFP_KERNEL);
+ if (!list->channels)
+ goto free;
+
+ for (i = 0; i < max_channel_num; i++) {
+ if (i < priv->iq_autocal_len) {
+ freq = le16_to_cpu(priv->iq_autocal[i].freq);
+ p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+ }
+
+ if (i < priv->output_limit->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ }
+
+ if (i < priv->curve_data->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->curve_data->entry_size +
+ priv->curve_data->offset +
+ priv->curve_data->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+ }
+ }
+
+ /* sort the list by the channel index */
+ sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+ p54_compare_channels, NULL);
+
+ for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+ if (list->band_channel_num[i]) {
+ ret = p54_generate_band(dev, list, i);
+ if (ret)
+ goto free;
+
+ j++;
+ }
+ }
+ if (j == 0) {
+ /* no useable band available. */
+ ret = -EINVAL;
+ }
+
+free:
+ if (list) {
+ kfree(list->channels);
+ kfree(list);
+ }
+
+ return ret;
+}
+
static int p54_convert_rev0(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
{
@@ -487,13 +670,19 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
goto err;
}
+ err = p54_generate_channel_lists(dev);
+ if (err)
+ goto err;
+
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ priv->band_table[IEEE80211_BAND_2GHZ];
if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
+ dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ priv->band_table[IEEE80211_BAND_5GHZ];
if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
priv->rx_diversity_mask = 3;
if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index c9a0545..f19add2 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -598,6 +598,10 @@ EXPORT_SYMBOL_GPL(p54_register_common);
void p54_free_common(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(priv->band_table[i]);
kfree(priv->iq_autocal);
kfree(priv->output_limit);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 6772ed5..584b156 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -198,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+ struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox