* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Luis Correia @ 2009-10-18 9:40 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Ivo van Doorn, John Linville, linux-wireless, users,
Alban Browaeys, Benoit PAPILLAULT, Felix Fietkau, Mattias Nissler,
Mark Asselstine, Xose Vazquez Perez, linux-kernel
In-Reply-To: <200910172318.56929.bzolnier@gmail.com>
On Sat, Oct 17, 2009 at 22:18, Bartlomiej Zolnierkiewicz
<bzolnier@gmail.com> wrote:
> On Saturday 17 October 2009 16:54:03 Bartlomiej Zolnierkiewicz wrote:
>>
>> [ I somehow missed this one by not being on cc: ]
>>
>> On Thursday 15 October 2009 22:04:14 Ivo van Doorn wrote:
>> > Add support for the rt2860/rt3090 chipsets from Ralink.
>> >
>> > Includes various patches from a lot of people who helped
>> > getting this driver into the current shape.
>> >
>> > Signed-off-by: Alban Browaeys <prahal@yahoo.com>
>> > Signed-off-by: Benoit PAPILLAULT <benoit.papillault@free.fr>
>> > Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>> > Signed-off-by: Luis Correia <luis.f.correia@gmail.com>
>> > Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de>
>> > Signed-off-by: Mark Asselstine <asselsm@gmail.com>
>> > Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
>> > Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
>> > ---
>> > http://kernel.org/pub/linux/kernel/people/ivd/patches/0003-rt2x00-Implement-support-for-rt2800pci.patch
>>
>> First let me say that I'm very happy to see this patch finally being
>> submitted and I appreciate the effort..
>>
>> (I'll give it a spin on Eee 901 w/ 2.6.32-rc5 sometime later..)
>
> Unfortunately still no luck with it, works just like it worked when I first
> tried it half a year ago (loads OK but "iwlist wlan0 scan" doesn't bring any
> results)..
>
> Could somebody with the genuine RT2860 revision of the chip try the driver
> and confirm that it works w/ 2.6.32-rc5 so I will know whether I should be
> looking for some generic problem or RT2880 revision specific one?
With my RaLink RT2760 Wireless 802.11n 1T/2R Cardbus [1814:0701], it
fails right after loading the firmware to the card.
(this is an internal PCI card, not cardbus)
Oct 16 23:08:15 lc kernel: phy0 -> rt2x00_set_chip: Info - Chipset
detected - rt: 0701, rf: 0003, rev: 28600102.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00lib_request_firmware: Info -
Loading firmware file 'rt2860.bin'.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00lib_request_firmware: Info -
Firmware detected - version: 0.11.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00pci_regbusy_read: Error -
Indirect register access failed: offset=0x00007010, value=0xffffffff
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00pci_regbusy_read: Error -
Indirect register access failed: offset=0x00007010, value=0xffffffff
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00pci_regbusy_read: Error -
Indirect register access failed: offset=0x00007010, value=0xffffffff
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00mac_conf_tx: Info -
Configured TX queue 0 - CWmin: 3, CWmax: 4, Aifs: 2, TXop: 102.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00mac_conf_tx: Info -
Configured TX queue 1 - CWmin: 4, CWmax: 5, Aifs: 2, TXop: 188.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00mac_conf_tx: Info -
Configured TX queue 2 - CWmin: 5, CWmax: 10, Aifs: 3, TXop: 0.
Oct 16 23:08:23 lc kernel: phy0 -> rt2x00mac_conf_tx: Info -
Configured TX queue 3 - CWmin: 5, CWmax: 10, Aifs: 7, TXop: 0.
We get those "regbusy errors" and then, the MCU no longer accepts any command.
Oddly though, it can scan and detect the surrounding AP's.
Luis Correia,
rt2x0 project admin
^ permalink raw reply
* Re: TL-WN721N
From: Azhar @ 2009-10-18 8:33 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20091015151058.GC2809@tuxdriver.com>
John W. Linville <linville@...> writes:
>
> On Thu, Oct 15, 2009 at 02:20:52PM +0000, Azhar wrote:
> > Hi all,
> >
> > I am looking for drivers of TL-WN721N (for linux)...i have been going through
> > pages aand pages of documentation....but every other link seems to route
> > here...i would really appreciate if you could guide me
> >
> > Thanks
> >
> > Azhar
>
> Is it PCI? USB? The output of lspci or lsusb would be helpful
> to know. Of course, in most cases you distribution would have the
> driver auto-loaded for you if it was supported at all...
>
> John
ndiswrapper -l
WARNING: All config files need .conf: /etc/modprobe.d/ndiswrapper, it will be
ignored in a future release.
WARNING: All config files need .conf: /etc/modprobe.d/blacklist, it will be
ignored in a future release.
netathur : driver installed
device (0CF3:9271) present
lsusb
Bus 001 Device 003: ID 0cf3:9271 Atheros Communications, Inc.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
^ permalink raw reply
* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Julian Calaby @ 2009-10-18 3:08 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Ivo van Doorn, John Linville, linux-wireless, users,
Alban Browaeys, Benoit PAPILLAULT, Felix Fietkau, Luis Correia,
Mattias Nissler, Mark Asselstine, Xose Vazquez Perez,
linux-kernel
In-Reply-To: <200910171654.03344.bzolnier@gmail.com>
On Sun, Oct 18, 2009 at 01:54, Bartlomiej Zolnierkiewicz
<bzolnier@gmail.com> wrote:
> Now to the less happy part..
>
> I also used the opportunity to take a closer look at this driver and
> it seems that it needlessly adds around 2 KLOC to kernel by duplicating
> the common content of rt2800usb.h to rt2800pci.h instead of moving it
> to the shared header (like it is done in the staging crap drivers):
>
> $ wc -l drivers/net/wireless/rt2x00/rt2800usb.h drivers/net/wireless/rt2x00/rt2800pci.h
> 1951 drivers/net/wireless/rt2x00/rt2800usb.h
> 1960 drivers/net/wireless/rt2x00/rt2800pci.h
> 3911 total
>
> $ diff -u drivers/net/wireless/rt2x00/rt2800usb.h drivers/net/wireless/rt2x00/rt2800pci.h|diffstat
> rt2800pci.h | 213 +++++++++++++++++++++++++++++++-----------------------------
> 1 file changed, 111 insertions(+), 102 deletions(-)
>
> Similarly it looks like most of the code between rt2800usb.c and rt2800pci.c
> could also be shared (up to another 2 KLOC saved) by adding abstraction layer
> for accessing chipset registers over different buses (again like it is done
> in staging crap drivers):
>
> $ wc -l drivers/net/wireless/rt2x00/rt2800usb.c drivers/net/wireless/rt2x00/rt2800pci.c
> 3077 drivers/net/wireless/rt2x00/rt2800usb.c
> 3323 drivers/net/wireless/rt2x00/rt2800pci.c
> 6400 total
>
> $ diff -u drivers/net/wireless/rt2x00/rt2800usb.c drivers/net/wireless/rt2x00/rt2800pci.c|diffstat
> rt2800pci.c | 2190 +++++++++++++++++++++++++++++++++---------------------------
> 1 file changed, 1218 insertions(+), 972 deletions(-)
Nobody else has said it, so:
Patches welcome!
Your points with the vendor drivers apply here too - consolidating the
common parts of the drivers will enhance readability, and make
development easier, and mean that, with your help, these might get to
a everyday usable state quicker.
And remember that this is a preliminary release of the code. There's
still a long way to go.
Thanks,
--
Julian Calaby
Email: julian.calaby@gmail.com
.Plan: http://sites.google.com/site/juliancalaby/
^ permalink raw reply
* Re: 2.6.32-rc0-git: oops in wireless, iwl3945 related?
From: Johannes Berg @ 2009-10-17 22:00 UTC (permalink / raw)
To: Pavel Machek; +Cc: linux-kernel, yi.zhu, reinette.chatre, linux-wireless
In-Reply-To: <20091017183320.GF16532@elf.ucw.cz>
[-- Attachment #1: Type: text/plain, Size: 1161 bytes --]
On Sat, 2009-10-17 at 20:33 +0200, Pavel Machek wrote:
> On Thu 2009-10-01 23:27:49, Johannes Berg wrote:
> > On Thu, 2009-10-01 at 23:16 +0200, Johannes Berg wrote:
> >
> > > > wlan0: Selected IBSS BSSID 02:18:41:de:3f:02 based on configured SSID
> > > > wlan0: Trigger new scan to find an IBSS to join
> > > > wlan0: Trigger new scan to find an IBSS to join
> > > > wlan0: Creating new IBSS network, BSSID f2:d3:80:82:ed:6a
> > > > wlan0: Creating new IBSS network, BSSID 52:17:bf:45:d6:9d
> > > > skb_over_panic: text:c07b4113 len:130 put:36 head:e4c3edf0
> > >
> > > This entire log is very odd ... can you reproduce this easily? printk
> > > timestamps would be useful.
> >
> > Kinda looks like a race condition, but it's rather odd. I think there's
> > a race condition, so I'm going to submit this patch regardless after
> > some testing, but if you want please try the patch below.
>
> Well, the problem is not exactly reproducible... it failed to happen
> again. So... thanks and I'll keep my eyes open if it returns.
Felix also found a bad condition (inverted) in the adhoc code, so that
might be related too.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Bartlomiej Zolnierkiewicz @ 2009-10-17 21:18 UTC (permalink / raw)
To: Ivo van Doorn
Cc: John Linville, linux-wireless, users, Alban Browaeys,
Benoit PAPILLAULT, Felix Fietkau, Luis Correia, Mattias Nissler,
Mark Asselstine, Xose Vazquez Perez, linux-kernel
In-Reply-To: <200910171654.03344.bzolnier@gmail.com>
On Saturday 17 October 2009 16:54:03 Bartlomiej Zolnierkiewicz wrote:
>
> [ I somehow missed this one by not being on cc: ]
>
> On Thursday 15 October 2009 22:04:14 Ivo van Doorn wrote:
> > Add support for the rt2860/rt3090 chipsets from Ralink.
> >
> > Includes various patches from a lot of people who helped
> > getting this driver into the current shape.
> >
> > Signed-off-by: Alban Browaeys <prahal@yahoo.com>
> > Signed-off-by: Benoit PAPILLAULT <benoit.papillault@free.fr>
> > Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> > Signed-off-by: Luis Correia <luis.f.correia@gmail.com>
> > Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de>
> > Signed-off-by: Mark Asselstine <asselsm@gmail.com>
> > Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
> > Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
> > ---
> > http://kernel.org/pub/linux/kernel/people/ivd/patches/0003-rt2x00-Implement-support-for-rt2800pci.patch
>
> First let me say that I'm very happy to see this patch finally being
> submitted and I appreciate the effort..
>
> (I'll give it a spin on Eee 901 w/ 2.6.32-rc5 sometime later..)
Unfortunately still no luck with it, works just like it worked when I first
tried it half a year ago (loads OK but "iwlist wlan0 scan" doesn't bring any
results)..
Could somebody with the genuine RT2860 revision of the chip try the driver
and confirm that it works w/ 2.6.32-rc5 so I will know whether I should be
looking for some generic problem or RT2880 revision specific one?
Thanks.
^ permalink raw reply
* [PATCH] [compat-2.6 and compat-2.6-stable] rename ieee80211_rx
From: Hauke Mehrtens @ 2009-10-17 21:06 UTC (permalink / raw)
To: lrodriguez; +Cc: linux-wireless, Hauke Mehrtens
Rename ieee80211_rx to avoild conflicts with the export done by older
libipw. libipw in kernel 2.6.32 and older also exports a symbol named
ieee80211_rx. If libipw from normal kernel and mac80211 from
compat-wireless is loaded you will get an conflict.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
compat/compat-2.6.32.h | 3 +++
compat/patches/15-symbol-export-conflicts.patch | 20 ++++++++++++++++++++
2 files changed, 23 insertions(+), 0 deletions(-)
create mode 100644 compat/patches/15-symbol-export-conflicts.patch
diff --git a/compat/compat-2.6.32.h b/compat/compat-2.6.32.h
index ad7f01b..1362e3e 100644
--- a/compat/compat-2.6.32.h
+++ b/compat/compat-2.6.32.h
@@ -71,6 +71,9 @@ struct dev_pm_ops name = { \
#define wireless_send_event(a, b, c, d) wireless_send_event(a, b, c, (char * ) d)
+/* The export symbol in changed in compat/patches/15-symbol-export-conflicts.patch */
+#define ieee80211_rx(hw, skb) mac80211_ieee80211_rx(hw, skb)
+
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)) */
#endif /* LINUX_26_32_COMPAT_H */
diff --git a/compat/patches/15-symbol-export-conflicts.patch b/compat/patches/15-symbol-export-conflicts.patch
new file mode 100644
index 0000000..e095f9b
--- /dev/null
+++ b/compat/patches/15-symbol-export-conflicts.patch
@@ -0,0 +1,20 @@
+In kernel < 2.6.32 libipw also exports ieee80211_rx.
+To avoid conflicts with the other export we rename our.
+
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index 5c385e3..26e5fc9 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2545,7 +2545,12 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+ drop:
+ kfree_skb(skb);
+ }
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+ EXPORT_SYMBOL(ieee80211_rx);
++#else
++EXPORT_SYMBOL(mac80211_ieee80211_rx);
++#endif
++
+
+ /* This is a version of the rx handler that can be called from hard irq
+ * context. Post the skb on the queue and schedule the tasklet */
--
1.6.2.1
^ permalink raw reply related
* Re: Issues building compat-wireless-2009-10-13
From: Philip A. Prindeville @ 2009-10-17 20:13 UTC (permalink / raw)
To: Riffer; +Cc: linux-wireless
In-Reply-To: <4AD6518D.2000709@penny.prima.de>
On 10/14/2009 03:32 PM, Riffer wrote:
> Hello!
>
> Give compat-wireless-2009-10-14 a try - it compiles and works against
> 2.6.30-02063006-generic.
>
I'm running that right now on an AR9160, with hostap-2009-10-13, but for whatever reason a Nokia E71 phone running release 200.something can't associate with a hidden AP using WPA2.
I'll see if I can expose any more clues...
^ permalink raw reply
* [PATCH 3/3] ar9170: don't filter BlockACK frames
From: Christian Lamparter @ 2009-10-17 19:56 UTC (permalink / raw)
To: linux-wireless; +Cc: linville
The current A-MPDU tx_status report mechanism is too inaccurate.
With this patch BlockACK frames show now up to the driver and
can be processed.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 611747d..b7d27dd 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -152,14 +152,14 @@ enum ar9170_cmd {
#define AR9170_MAC_REG_FTF_BIT14 BIT(14)
#define AR9170_MAC_REG_FTF_BIT15 BIT(15)
#define AR9170_MAC_REG_FTF_BAR BIT(24)
-#define AR9170_MAC_REG_FTF_BIT25 BIT(25)
+#define AR9170_MAC_REG_FTF_BA BIT(25)
#define AR9170_MAC_REG_FTF_PSPOLL BIT(26)
#define AR9170_MAC_REG_FTF_RTS BIT(27)
#define AR9170_MAC_REG_FTF_CTS BIT(28)
#define AR9170_MAC_REG_FTF_ACK BIT(29)
#define AR9170_MAC_REG_FTF_CFE BIT(30)
#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31)
-#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff
+#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff
#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff
#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0)
^ permalink raw reply related
* [PATCH 2/3] ar9170usb: atomic pending urbs counter
From: Christian Lamparter @ 2009-10-17 19:56 UTC (permalink / raw)
To: linux-wireless; +Cc: linville
This patch follows "ar9170: atomic pending A-MPDU counter"
idea and converts another critical counter to atomic_*.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e974e58..6bdcdf6 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -108,15 +108,15 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
return ;
spin_lock_irqsave(&aru->tx_urb_lock, flags);
- if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
+ if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
}
- aru->tx_submitted_urbs++;
+ atomic_inc(&aru->tx_submitted_urbs);
urb = usb_get_from_anchor(&aru->tx_pending);
if (!urb) {
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
@@ -133,7 +133,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
err);
usb_unanchor_urb(urb);
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, urb->context);
}
@@ -151,7 +151,7 @@ static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
return ;
}
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, skb);
@@ -794,7 +794,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0;
- aru->tx_submitted_urbs = 0;
+ atomic_set(&aru->tx_submitted_urbs, 0);
aru->common.stop = ar9170_usb_stop;
aru->common.flush = ar9170_usb_flush;
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index d098f4d..a2ce3b1 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -67,7 +67,7 @@ struct ar9170_usb {
bool req_one_stage_fw;
spinlock_t tx_urb_lock;
- unsigned int tx_submitted_urbs;
+ atomic_t tx_submitted_urbs;
unsigned int tx_pending_urbs;
struct completion cmd_wait;
^ permalink raw reply related
* [PATCH 1/3] ar9170: atomic pending A-MPDU counter
From: Christian Lamparter @ 2009-10-17 19:56 UTC (permalink / raw)
To: linux-wireless; +Cc: linville
A ref-counting bug emerged after testing ar9170usb's HT
implementation on a bigger SMP/SMT system without the usual
_debugging_ overhead.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
Just in case: all patches are for wireless-testing.
I don't think it's critical, since the A-MPDU can't
be enabled in vanilla anyway...
---
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index ec034af..9f94598 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -231,7 +231,7 @@ struct ar9170 {
struct sk_buff_head tx_status_ampdu;
spinlock_t tx_ampdu_list_lock;
struct list_head tx_ampdu_list;
- unsigned int tx_ampdu_pending;
+ atomic_t tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index de0ba2b..7e59b82 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -414,9 +414,9 @@ static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
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)
+ if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
+ !list_empty(&ar->tx_ampdu_list))
ar9170_tx_ampdu(ar);
}
@@ -1248,6 +1248,7 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3;
+ atomic_set(&ar->tx_ampdu_pending, 0);
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1773,7 +1774,7 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_TX_TIMEOUT);
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
- ar->tx_ampdu_pending++;
+ atomic_inc(&ar->tx_ampdu_pending);
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
@@ -1784,7 +1785,7 @@ 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--;
+ atomic_dec(&ar->tx_ampdu_pending);
frames_failed++;
dev_kfree_skb_any(skb);
@@ -1931,7 +1932,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
bool run = ar9170_tx_ampdu_queue(ar, skb);
- if (run || !ar->tx_ampdu_pending)
+ if (run || !atomic_read(&ar->tx_ampdu_pending))
ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
^ permalink raw reply related
* [PATCH net-next V2 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Tomas Winkler @ 2009-10-17 19:09 UTC (permalink / raw)
To: davem, linville, netdev, linux-wireless, linux-mmc
Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
ron.rindjunsky, Tomas Winkler
This patch adds Intel Wireless MultiCom 3200 top driver.
IWMC3200 is 4Wireless Com CHIP (GPS/BT/WiFi/WiMAX).
Top driver is responsible for device initialization and firmware download.
Firmware handled by top is responsible for top itself and
as well as bluetooth and GPS coms. (Wifi and WiMax provide their own firmware)
In addition top driver is used to retrieve firmware logs
and supports other debugging features
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. fixing barker management
2. use dev_get_drvdata instead of d->driver_data
3. cleanup debugfs
drivers/misc/Kconfig | 1 +
drivers/misc/Makefile | 1 +
drivers/misc/iwmc3200top/Kconfig | 20 +
drivers/misc/iwmc3200top/Makefile | 29 ++
drivers/misc/iwmc3200top/debugfs.c | 133 ++++++
drivers/misc/iwmc3200top/debugfs.h | 58 +++
drivers/misc/iwmc3200top/fw-download.c | 359 ++++++++++++++++
drivers/misc/iwmc3200top/fw-msg.h | 113 +++++
drivers/misc/iwmc3200top/iwmc3200top.h | 206 ++++++++++
drivers/misc/iwmc3200top/log.c | 347 ++++++++++++++++
drivers/misc/iwmc3200top/log.h | 158 +++++++
drivers/misc/iwmc3200top/main.c | 699 ++++++++++++++++++++++++++++++++
12 files changed, 2124 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/iwmc3200top/Kconfig
create mode 100644 drivers/misc/iwmc3200top/Makefile
create mode 100644 drivers/misc/iwmc3200top/debugfs.c
create mode 100644 drivers/misc/iwmc3200top/debugfs.h
create mode 100644 drivers/misc/iwmc3200top/fw-download.c
create mode 100644 drivers/misc/iwmc3200top/fw-msg.h
create mode 100644 drivers/misc/iwmc3200top/iwmc3200top.h
create mode 100644 drivers/misc/iwmc3200top/log.c
create mode 100644 drivers/misc/iwmc3200top/log.h
create mode 100644 drivers/misc/iwmc3200top/main.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index df1f86b..a2ea383 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -249,5 +249,6 @@ config EP93XX_PWM
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
+source "drivers/misc/iwmc3200top/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f982d2e..e311267 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_ISL29003) += isl29003.o
obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_C2PORT) += c2port/
+obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
obj-y += eeprom/
obj-y += cb710/
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig
new file mode 100644
index 0000000..9e4b88f
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Kconfig
@@ -0,0 +1,20 @@
+config IWMC3200TOP
+ tristate "Intel Wireless MultiCom Top Driver"
+ depends on MMC && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ Intel Wireless MultiCom 3200 Top driver is responsible for
+ for firmware load and enabled coms enumeration
+
+config IWMC3200TOP_DEBUG
+ bool "Enable full debug output of iwmc3200top Driver"
+ depends on IWMC3200TOP
+ ---help---
+ Enable full debug output of iwmc3200top Driver
+
+config IWMC3200TOP_DEBUGFS
+ bool "Enable Debugfs debugging interface for iwmc3200top"
+ depends on IWMC3200TOP
+ ---help---
+ Enable creation of debugfs files for iwmc3200top
+
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile
new file mode 100644
index 0000000..fbf53fb
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Makefile
@@ -0,0 +1,29 @@
+# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+# drivers/misc/iwmc3200top/Makefile
+#
+# Copyright (C) 2009 Intel Corporation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version
+# 2 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+#
+# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+# -
+#
+#
+
+obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o
+iwmc3200top-objs := main.o fw-download.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c
new file mode 100644
index 0000000..0c8ea0a
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.c
@@ -0,0 +1,133 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+#include <linux/debugfs.h>
+
+#include "iwmc3200top.h"
+#include "fw-msg.h"
+#include "log.h"
+#include "debugfs.h"
+
+
+
+/* Constants definition */
+#define HEXADECIMAL_RADIX 16
+
+/* Functions definition */
+
+
+#define DEBUGFS_ADD(name, parent) do { \
+ dbgfs->dbgfs_##parent##_files.file_##name = \
+ debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ &iwmct_dbgfs_##name##_ops); \
+} while (0)
+
+#define DEBUGFS_RM(name) do { \
+ debugfs_remove(name); \
+ name = NULL; \
+} while (0)
+
+#define DEBUGFS_READ_FUNC(name) \
+ssize_t iwmct_dbgfs_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name) \
+ssize_t iwmct_dbgfs_##name##_write(struct file *file, \
+ const char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+#define DEBUGFS_READ_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = { \
+ .read = iwmct_dbgfs_##name##_read, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+#define DEBUGFS_WRITE_FILE_OPS(name) \
+ DEBUGFS_WRITE_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = { \
+ .write = iwmct_dbgfs_##name##_write, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name) \
+ DEBUGFS_WRITE_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = {\
+ .write = iwmct_dbgfs_##name##_write, \
+ .read = iwmct_dbgfs_##name##_read, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+
+/* Debugfs file ops definitions */
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{
+ struct iwmct_debugfs *dbgfs;
+
+ dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
+ if (!dbgfs) {
+ LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
+ sizeof(struct iwmct_debugfs));
+ return;
+ }
+
+ priv->dbgfs = dbgfs;
+ dbgfs->name = name;
+ dbgfs->dir_drv = debugfs_create_dir(name, NULL);
+ if (!dbgfs->dir_drv) {
+ LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
+ return;
+ }
+
+ return;
+}
+
+/**
+ * Remove the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{
+ if (!dbgfs)
+ return;
+
+ DEBUGFS_RM(dbgfs->dir_drv);
+ kfree(dbgfs);
+ dbgfs = NULL;
+}
+
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h
new file mode 100644
index 0000000..71d4575
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.h
@@ -0,0 +1,58 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __DEBUGFS_H__
+#define __DEBUGFS_H__
+
+
+#ifdef CONFIG_IWMC3200TOP_DEBUGFS
+
+struct iwmct_debugfs {
+ const char *name;
+ struct dentry *dir_drv;
+ struct dir_drv_files {
+ } dbgfs_drv_files;
+};
+
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
+
+#else /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+struct iwmct_debugfs;
+
+static inline void
+iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{}
+
+static inline void
+iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{}
+
+#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+#endif /* __DEBUGFS_H__ */
+
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c
new file mode 100644
index 0000000..33cb693
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-download.c
@@ -0,0 +1,359 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-download.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/mmc/sdio_func.h>
+#include <asm/unaligned.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+
+#define CHECKSUM_BYTES_NUM sizeof(u32)
+
+/**
+ init parser struct with file
+ */
+static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
+ size_t file_size, size_t block_size)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_hdr *fw_hdr = &parser->versions;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
+
+ parser->file = file;
+ parser->file_size = file_size;
+ parser->cur_pos = 0;
+ parser->buf = NULL;
+
+ parser->buf = kzalloc(block_size, GFP_KERNEL);
+ if (!parser->buf) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
+ return -ENOMEM;
+ }
+ parser->buf_size = block_size;
+
+ /* extract fw versions */
+ memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr));
+ LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n"
+ "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n",
+ fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision,
+ fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision,
+ fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision,
+ fw_hdr->tic_name);
+
+ parser->cur_pos += sizeof(struct iwmct_fw_hdr);
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+static bool iwmct_checksum(struct iwmct_priv *priv)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ __le32 *file = (__le32 *)parser->file;
+ int i, pad, steps;
+ u32 accum = 0;
+ u32 checksum;
+ u32 mask = 0xffffffff;
+
+ pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4;
+ steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4;
+
+ LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps);
+
+ for (i = 0; i < steps; i++)
+ accum += le32_to_cpu(file[i]);
+
+ if (pad) {
+ mask <<= 8 * (4 - pad);
+ accum += le32_to_cpu(file[steps]) & mask;
+ }
+
+ checksum = get_unaligned_le32((__le32 *)(parser->file +
+ parser->file_size - CHECKSUM_BYTES_NUM));
+
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "compare checksum accum=0x%x to checksum=0x%x\n",
+ accum, checksum);
+
+ return checksum == accum;
+}
+
+static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
+ size_t *sec_size, __le32 *sec_addr)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_dbg *dbg = &priv->dbg;
+ struct iwmct_fw_sec_hdr *sec_hdr;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
+ <= parser->file_size) {
+
+ sec_hdr = (struct iwmct_fw_sec_hdr *)
+ (parser->file + parser->cur_pos);
+ parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr);
+
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "sec hdr: type=%s addr=0x%x size=%d\n",
+ sec_hdr->type, sec_hdr->target_addr,
+ sec_hdr->data_size);
+
+ if (strcmp(sec_hdr->type, "ENT") == 0)
+ parser->entry_point = le32_to_cpu(sec_hdr->target_addr);
+ else if (strcmp(sec_hdr->type, "LBL") == 0)
+ strcpy(dbg->label_fw, parser->file + parser->cur_pos);
+ else if (((strcmp(sec_hdr->type, "TOP") == 0) &&
+ (priv->barker & BARKER_DNLOAD_TOP_MSK)) ||
+ ((strcmp(sec_hdr->type, "GPS") == 0) &&
+ (priv->barker & BARKER_DNLOAD_GPS_MSK)) ||
+ ((strcmp(sec_hdr->type, "BTH") == 0) &&
+ (priv->barker & BARKER_DNLOAD_BT_MSK))) {
+ *sec_addr = sec_hdr->target_addr;
+ *sec_size = le32_to_cpu(sec_hdr->data_size);
+ *p_sec = parser->file + parser->cur_pos;
+ parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+ return 1;
+ } else if (strcmp(sec_hdr->type, "LOG") != 0)
+ LOG_WARNING(priv, FW_DOWNLOAD,
+ "skipping section type %s\n",
+ sec_hdr->type);
+
+ parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "finished with section cur_pos=%zd\n", parser->cur_pos);
+ }
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
+ size_t sec_size, __le32 addr)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+ const u8 *cur_block = p_sec;
+ size_t sent = 0;
+ int cnt = 0;
+ int ret = 0;
+ u32 cmd = 0;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
+ addr, sec_size);
+
+ while (sent < sec_size) {
+ int i;
+ u32 chksm = 0;
+ u32 reset = atomic_read(&priv->reset);
+ /* actual FW data */
+ u32 data_size = min(parser->buf_size - sizeof(*hdr),
+ sec_size - sent);
+ /* Pad to block size */
+ u32 trans_size = (data_size + sizeof(*hdr) +
+ IWMC_SDIO_BLK_SIZE - 1) &
+ ~(IWMC_SDIO_BLK_SIZE - 1);
+ ++cnt;
+
+ /* in case of reset, interrupt FW DOWNLAOD */
+ if (reset) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "Reset detected. Abort FW download!!!");
+ ret = -ECANCELED;
+ goto exit;
+ }
+
+ memset(parser->buf, 0, parser->buf_size);
+ cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
+ cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+ cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
+ cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
+ hdr->data_size = cpu_to_le32(data_size);
+ hdr->target_addr = addr;
+
+ /* checksum is allowed for sizes divisible by 4 */
+ if (data_size & 0x3)
+ cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;
+
+ memcpy(hdr->data, cur_block, data_size);
+
+
+ if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {
+
+ chksm = data_size + le32_to_cpu(addr) + cmd;
+ for (i = 0; i < data_size >> 2; i++)
+ chksm += ((u32 *)cur_block)[i];
+
+ hdr->block_chksm = cpu_to_le32(chksm);
+ LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
+ hdr->block_chksm);
+ }
+
+ LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
+ "sec_size=%zd, startAddress 0x%X\n",
+ cnt, trans_size, sent, sec_size, addr);
+
+ if (priv->dbg.dump)
+ LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);
+
+
+ hdr->cmd = cpu_to_le32(cmd);
+ /* send it down */
+ /* TODO: add more proper sending and error checking */
+ ret = iwmct_tx(priv, 0, parser->buf, trans_size);
+ if (ret != 0) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "iwmct_tx returned %d\n", ret);
+ goto exit;
+ }
+
+ addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
+ sent += data_size;
+ cur_block = p_sec + sent;
+
+ if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "Block number limit is reached [%d]\n",
+ priv->dbg.blocks);
+ break;
+ }
+ }
+
+ if (sent < sec_size)
+ ret = -EINVAL;
+exit:
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return ret;
+}
+
+static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+ int ret;
+ u32 cmd;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ memset(parser->buf, 0, parser->buf_size);
+ cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+ if (jump) {
+ cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
+ hdr->target_addr = cpu_to_le32(parser->entry_point);
+ LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
+ parser->entry_point);
+ } else {
+ cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
+ LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
+ }
+
+ hdr->cmd = cpu_to_le32(cmd);
+
+ LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
+ /* send it down */
+ /* TODO: add more proper sending and error checking */
+ ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
+ if (ret)
+ LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+int iwmct_fw_load(struct iwmct_priv *priv)
+{
+ const struct firmware *raw = NULL;
+ __le32 addr;
+ size_t len;
+ const u8 *pdata;
+ const u8 *name = "iwmc3200top.1.fw";
+ int ret = 0;
+
+ /* clear parser struct */
+ memset(&priv->parser, 0, sizeof(struct iwmct_parser));
+ if (!name) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* get the firmware */
+ ret = request_firmware(&raw, name, &priv->func->dev);
+ if (ret < 0) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n",
+ name, ret);
+ goto exit;
+ }
+
+ if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n",
+ name, sizeof(struct iwmct_fw_sec_hdr), raw->size);
+ goto exit;
+ }
+
+ LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", name);
+
+ ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
+ if (ret < 0) {
+ LOG_ERROR(priv, FW_DOWNLOAD,
+ "iwmct_parser_init failed: Reason %d\n", ret);
+ goto exit;
+ }
+
+ /* checksum */
+ if (!iwmct_checksum(priv)) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* download firmware to device */
+ while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
+ if (iwmct_download_section(priv, pdata, len, addr)) {
+ LOG_ERROR(priv, FW_DOWNLOAD,
+ "%s download section failed\n", name);
+ ret = -EIO;
+ goto exit;
+ }
+ }
+
+ iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
+
+exit:
+ kfree(priv->parser.buf);
+
+ if (raw)
+ release_firmware(raw);
+
+ raw = NULL;
+
+ return ret;
+}
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h
new file mode 100644
index 0000000..9e26b75
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-msg.h
@@ -0,0 +1,113 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-msg.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __FWMSG_H__
+#define __FWMSG_H__
+
+#define COMM_TYPE_D2H 0xFF
+#define COMM_TYPE_H2D 0xEE
+
+#define COMM_CATEGORY_OPERATIONAL 0x00
+#define COMM_CATEGORY_DEBUG 0x01
+#define COMM_CATEGORY_TESTABILITY 0x02
+#define COMM_CATEGORY_DIAGNOSTICS 0x03
+
+#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A)
+
+#define FW_LOG_SRC_MAX 32
+#define FW_LOG_SRC_ALL 255
+
+#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000)
+
+#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001)
+#define CMD_TST_DEV_RESET cpu_to_le16(0x0060)
+#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062)
+#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064)
+#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065)
+#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080)
+#define CMD_TST_WAKEUP cpu_to_le16(0x0081)
+#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082)
+#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083)
+#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096)
+
+#define OP_OPR_ALIVE cpu_to_le16(0x0010)
+#define OP_OPR_CMD_ACK cpu_to_le16(0x001F)
+#define OP_OPR_CMD_NACK cpu_to_le16(0x0020)
+#define OP_TST_MEM_DUMP cpu_to_le16(0x0043)
+
+#define CMD_FLAG_PADDING_256 0x80
+
+#define FW_HCMD_BLOCK_SIZE 256
+
+struct msg_hdr {
+ u8 type;
+ u8 category;
+ __le16 opcode;
+ u8 seqnum;
+ u8 flags;
+ __le16 length;
+} __attribute__((__packed__));
+
+struct log_hdr {
+ __le32 timestamp;
+ u8 severity;
+ u8 logsource;
+ __le16 reserved;
+} __attribute__((__packed__));
+
+struct mdump_hdr {
+ u8 dmpid;
+ u8 frag;
+ __le16 size;
+ __le32 addr;
+} __attribute__((__packed__));
+
+struct top_msg {
+ struct msg_hdr hdr;
+ union {
+ /* D2H messages */
+ struct {
+ struct log_hdr log_hdr;
+ u8 data[1];
+ } __attribute__((__packed__)) log;
+
+ struct {
+ struct log_hdr log_hdr;
+ struct mdump_hdr md_hdr;
+ u8 data[1];
+ } __attribute__((__packed__)) mdump;
+
+ /* H2D messages */
+ struct {
+ u8 logsource;
+ u8 sevmask;
+ } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
+ struct mdump_hdr mdump_req;
+ } u;
+} __attribute__((__packed__));
+
+
+#endif /* __FWMSG_H__ */
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h
new file mode 100644
index 0000000..f572fcf
--- /dev/null
+++ b/drivers/misc/iwmc3200top/iwmc3200top.h
@@ -0,0 +1,206 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/iwmc3200top.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __IWMC3200TOP_H__
+#define __IWMC3200TOP_H__
+
+#include <linux/workqueue.h>
+
+#define DRV_NAME "iwmc3200top"
+
+#define IWMC_SDIO_BLK_SIZE 256
+#define IWMC_DEFAULT_TR_BLK 64
+#define IWMC_SDIO_DATA_ADDR 0x0
+#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14
+#define IWMC_SDIO_INTR_STATUS_ADDR 0x13
+#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13
+#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C
+
+#define COMM_HUB_HEADER_LENGTH 16
+#define LOGGER_HEADER_LENGTH 10
+
+
+#define BARKER_DNLOAD_BT_POS 0
+#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS)
+#define BARKER_DNLOAD_GPS_POS 1
+#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS)
+#define BARKER_DNLOAD_TOP_POS 2
+#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS)
+#define BARKER_DNLOAD_RESERVED1_POS 3
+#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS)
+#define BARKER_DNLOAD_JUMP_POS 4
+#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS)
+#define BARKER_DNLOAD_SYNC_POS 5
+#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS)
+#define BARKER_DNLOAD_RESERVED2_POS 6
+#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS)
+#define BARKER_DNLOAD_BARKER_POS 8
+#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS)
+
+#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS)
+/* whole field barker */
+#define IWMC_BARKER_ACK 0xfeedbabe
+
+#define IWMC_CMD_SIGNATURE 0xcbbc
+
+#define CMD_HDR_OPCODE_POS 0
+#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS)
+#define CMD_HDR_RESPONSE_CODE_POS 4
+#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS)
+#define CMD_HDR_USE_CHECKSUM_POS 8
+#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS)
+#define CMD_HDR_RESPONSE_REQUIRED_POS 9
+#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
+#define CMD_HDR_DIRECT_ACCESS_POS 10
+#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS)
+#define CMD_HDR_RESERVED_POS 11
+#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS)
+#define CMD_HDR_SIGNATURE_POS 16
+#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS)
+
+enum {
+ IWMC_OPCODE_PING = 0,
+ IWMC_OPCODE_READ = 1,
+ IWMC_OPCODE_WRITE = 2,
+ IWMC_OPCODE_JUMP = 3,
+ IWMC_OPCODE_REBOOT = 4,
+ IWMC_OPCODE_PERSISTENT_WRITE = 5,
+ IWMC_OPCODE_PERSISTENT_READ = 6,
+ IWMC_OPCODE_READ_MODIFY_WRITE = 7,
+ IWMC_OPCODE_LAST_COMMAND = 15
+};
+
+struct iwmct_fw_load_hdr {
+ __le32 cmd;
+ __le32 target_addr;
+ __le32 data_size;
+ __le32 block_chksm;
+ u8 data[0];
+};
+
+/**
+ * struct iwmct_fw_hdr
+ * holds all sw components versions
+ */
+struct iwmct_fw_hdr {
+ u8 top_major;
+ u8 top_minor;
+ u8 top_revision;
+ u8 gps_major;
+ u8 gps_minor;
+ u8 gps_revision;
+ u8 bt_major;
+ u8 bt_minor;
+ u8 bt_revision;
+ u8 tic_name[31];
+};
+
+/**
+ * struct iwmct_fw_sec_hdr
+ * @type: function type
+ * @data_size: section's data size
+ * @target_addr: download address
+ */
+struct iwmct_fw_sec_hdr {
+ u8 type[4];
+ __le32 data_size;
+ __le32 target_addr;
+};
+
+/**
+ * struct iwmct_parser
+ * @file: fw image
+ * @file_size: fw size
+ * @cur_pos: position in file
+ * @buf: temp buf for download
+ * @buf_size: size of buf
+ * @entry_point: address to jump in fw kick-off
+ */
+struct iwmct_parser {
+ const u8 *file;
+ size_t file_size;
+ size_t cur_pos;
+ u8 *buf;
+ size_t buf_size;
+ u32 entry_point;
+ struct iwmct_fw_hdr versions;
+};
+
+
+struct iwmct_work_struct {
+ struct list_head list;
+ ssize_t iosize;
+};
+
+struct iwmct_dbg {
+ int blocks;
+ bool dump;
+ bool jump;
+ bool direct;
+ bool checksum;
+ bool fw_download;
+ int block_size;
+ int download_trans_blks;
+
+ char label_fw[256];
+};
+
+struct iwmct_debugfs;
+
+struct iwmct_priv {
+ struct sdio_func *func;
+ struct iwmct_debugfs *dbgfs;
+ struct iwmct_parser parser;
+ atomic_t reset;
+ atomic_t dev_sync;
+ u32 trans_len;
+ u32 barker;
+ struct iwmct_dbg dbg;
+
+ /* drivers work queue */
+ struct workqueue_struct *wq;
+ struct workqueue_struct *bus_rescan_wq;
+ struct work_struct bus_rescan_worker;
+ struct work_struct isr_worker;
+
+ /* drivers wait queue */
+ wait_queue_head_t wait_q;
+
+ /* rx request list */
+ struct list_head read_req_list;
+};
+
+extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+ void *src, int count);
+
+extern int iwmct_fw_load(struct iwmct_priv *priv);
+
+extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
+extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
+extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
+extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
+
+#endif /* __IWMC3200TOP_H__ */
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c
new file mode 100644
index 0000000..d569279
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.c
@@ -0,0 +1,347 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/ctype.h>
+#include "fw-msg.h"
+#include "iwmc3200top.h"
+#include "log.h"
+
+/* Maximal hexadecimal string size of the FW memdump message */
+#define LOG_MSG_SIZE_MAX 12400
+
+/* iwmct_logdefs is a global used by log macros */
+u8 iwmct_logdefs[LOG_SRC_MAX];
+static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
+
+
+static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
+{
+ int i;
+
+ if (src < size)
+ logdefs[src] = logmask;
+ else if (src == LOG_SRC_ALL)
+ for (i = 0; i < size; i++)
+ logdefs[i] = logmask;
+ else
+ return -1;
+
+ return 0;
+}
+
+
+int iwmct_log_set_filter(u8 src, u8 logmask)
+{
+ return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
+}
+
+
+int iwmct_log_set_fw_filter(u8 src, u8 logmask)
+{
+ return _log_set_log_filter(iwmct_fw_logdefs,
+ FW_LOG_SRC_MAX, src, logmask);
+}
+
+
+static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
+ int ilen, char *pref)
+{
+ int pos = 0;
+ int i;
+ int len;
+
+ for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
+ str[pos] = pref[i];
+
+ for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
+ len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
+
+ if (i < ilen)
+ return -1;
+
+ return 0;
+}
+
+/* NOTE: This function is not thread safe.
+ Currently it's called only from sdio rx worker - no race there
+*/
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+ struct top_msg *msg;
+ static char logbuf[LOG_MSG_SIZE_MAX];
+
+ msg = (struct top_msg *)buf;
+
+ if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
+ LOG_ERROR(priv, FW_MSG, "Log message from TOP "
+ "is too short %d (expected %zd)\n",
+ len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
+ return;
+ }
+
+ if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
+ BIT(msg->u.log.log_hdr.severity)) ||
+ !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
+ return;
+
+ switch (msg->hdr.category) {
+ case COMM_CATEGORY_TESTABILITY:
+ if (!(iwmct_logdefs[LOG_SRC_TST] &
+ BIT(msg->u.log.log_hdr.severity)))
+ return;
+ if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+ le16_to_cpu(msg->hdr.length) +
+ sizeof(msg->hdr), "<TST>"))
+ LOG_WARNING(priv, TST,
+ "TOP TST message is too long, truncating...");
+ LOG_WARNING(priv, TST, "%s\n", logbuf);
+ break;
+ case COMM_CATEGORY_DEBUG:
+ if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
+ LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
+ ((u8 *)msg) + sizeof(msg->hdr)
+ + sizeof(msg->u.log.log_hdr));
+ else {
+ if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+ le16_to_cpu(msg->hdr.length)
+ + sizeof(msg->hdr),
+ "<DBG>"))
+ LOG_WARNING(priv, FW_MSG,
+ "TOP DBG message is too long,"
+ "truncating...");
+ LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
+{
+ int i, pos, len;
+ for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
+ len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
+ i, logdefs[i]);
+ pos += len;
+ }
+ buf[pos-1] = '\n';
+ buf[pos] = '\0';
+
+ if (i < logdefsz)
+ return -1;
+ return 0;
+}
+
+int log_get_filter_str(char *buf, int size)
+{
+ return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
+}
+
+int log_get_fw_filter_str(char *buf, int size)
+{
+ return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
+}
+
+#define HEXADECIMAL_RADIX 16
+#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
+
+ssize_t show_iwmct_log_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *str_buf;
+ int buf_size;
+ ssize_t ret;
+
+ buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
+ str_buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %d bytes\n", buf_size);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (log_get_filter_str(str_buf, buf_size) < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = sprintf(buf, "%s", str_buf);
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t store_iwmct_log_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *token, *str_buf = NULL;
+ long val;
+ ssize_t ret = count;
+ u8 src, mask;
+
+ if (!count)
+ goto exit;
+
+ str_buf = kzalloc(count, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %zd bytes\n", count);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(str_buf, buf, count);
+
+ while ((token = strsep(&str_buf, ",")) != NULL) {
+ while (isspace(*token))
+ ++token;
+ if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to convert string to long %s\n",
+ token);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ mask = val & 0xFF;
+ src = (val & 0XFF00) >> 8;
+ iwmct_log_set_filter(src, mask);
+ }
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t show_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *str_buf;
+ int buf_size;
+ ssize_t ret;
+
+ buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
+
+ str_buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %d bytes\n", buf_size);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = sprintf(buf, "%s", str_buf);
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t store_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ struct top_msg cmd;
+ char *token, *str_buf = NULL;
+ ssize_t ret = count;
+ u16 cmdlen = 0;
+ int i;
+ long val;
+ u8 src, mask;
+
+ if (!count)
+ goto exit;
+
+ str_buf = kzalloc(count, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %zd bytes\n", count);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(str_buf, buf, count);
+
+ cmd.hdr.type = COMM_TYPE_H2D;
+ cmd.hdr.category = COMM_CATEGORY_DEBUG;
+ cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
+
+ for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
+ (i < FW_LOG_SRC_MAX); i++) {
+
+ while (isspace(*token))
+ ++token;
+
+ if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to convert string to long %s\n",
+ token);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ mask = val & 0xFF; /* LSB */
+ src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
+ iwmct_log_set_fw_filter(src, mask);
+
+ cmd.u.logdefs[i].logsource = src;
+ cmd.u.logdefs[i].sevmask = mask;
+ }
+
+ cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
+ cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
+
+ ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
+ if (ret) {
+ LOG_ERROR(priv, DEBUGFS,
+ "Failed to send %d bytes of fwcmd, ret=%zd\n",
+ cmdlen, ret);
+ goto exit;
+ } else
+ LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
+
+ ret = count;
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h
new file mode 100644
index 0000000..aba8121
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.h
@@ -0,0 +1,158 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+
+/* log severity:
+ * The log levels here match FW log levels
+ * so values need to stay as is */
+#define LOG_SEV_CRITICAL 0
+#define LOG_SEV_ERROR 1
+#define LOG_SEV_WARNING 2
+#define LOG_SEV_INFO 3
+#define LOG_SEV_INFOEX 4
+
+#define LOG_SEV_FILTER_ALL \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING) | \
+ BIT(LOG_SEV_INFO) | \
+ BIT(LOG_SEV_INFOEX))
+
+/* log source */
+#define LOG_SRC_INIT 0
+#define LOG_SRC_DEBUGFS 1
+#define LOG_SRC_FW_DOWNLOAD 2
+#define LOG_SRC_FW_MSG 3
+#define LOG_SRC_TST 4
+#define LOG_SRC_IRQ 5
+
+#define LOG_SRC_MAX 6
+#define LOG_SRC_ALL 0xFF
+
+/**
+ * Default intitialization runtime log level
+ */
+#ifndef LOG_SEV_FILTER_RUNTIME
+#define LOG_SEV_FILTER_RUNTIME \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING))
+#endif
+
+#ifndef FW_LOG_SEV_FILTER_RUNTIME
+#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+/**
+ * Log macros
+ */
+
+#define priv2dev(priv) (&(priv->func)->dev)
+
+#define LOG_CRITICAL(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \
+ dev_crit(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_ERROR(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \
+ dev_err(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_WARNING(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \
+ dev_warn(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_INFO(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \
+ dev_info(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_INFOEX(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ dev_dbg(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_HEXDUMP(src, ptr, len) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
+ 16, 1, ptr, len, false); \
+} while (0)
+
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
+
+extern u8 iwmct_logdefs[];
+
+int iwmct_log_set_filter(u8 src, u8 logmask);
+int iwmct_log_set_fw_filter(u8 src, u8 logmask);
+
+ssize_t show_iwmct_log_level(struct device *d,
+ struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+ssize_t show_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+#else
+
+#define LOG_CRITICAL(priv, src, fmt, args...)
+#define LOG_ERROR(priv, src, fmt, args...)
+#define LOG_WARNING(priv, src, fmt, args...)
+#define LOG_INFO(priv, src, fmt, args...)
+#define LOG_INFOEX(priv, src, fmt, args...)
+#define LOG_HEXDUMP(src, ptr, len)
+
+static inline void iwmct_log_top_message(struct iwmct_priv *priv,
+ u8 *buf, int len) {}
+static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
+static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
+
+#endif /* CONFIG_IWMC3200TOP_DEBUG */
+
+int log_get_filter_str(char *buf, int size);
+int log_get_fw_filter_str(char *buf, int size);
+
+#endif /* __LOG_H__ */
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
new file mode 100644
index 0000000..6e4e491
--- /dev/null
+++ b/drivers/misc/iwmc3200top/main.c
@@ -0,0 +1,699 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/main.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+#include "debugfs.h"
+
+
+#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver"
+#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation."
+
+#define IWMCT_VERSION "0.1.62"
+
+#ifdef REPOSITORY_LABEL
+#define RL REPOSITORY_LABEL
+#else
+#define RL local
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+#define VD "-d"
+#else
+#define VD
+#endif
+
+#define DRIVER_VERSION IWMCT_VERSION "-" __stringify(RL) VD
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_COPYRIGHT);
+
+
+/* FIXME: These can be found in sdio_ids.h in newer kernels */
+#ifndef SDIO_INTEL_VENDOR_ID
+#define SDIO_INTEL_VENDOR_ID 0x0089
+#endif
+#ifndef SDIO_DEVICE_ID_INTEL_IWMC3200TOP
+#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
+#endif
+
+/*
+ * This workers main task is to wait for OP_OPR_ALIVE
+ * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
+ * When OP_OPR_ALIVE received it will issue
+ * a call to "bus_rescan_devices".
+ */
+static void iwmct_rescan_worker(struct work_struct *ws)
+{
+ struct iwmct_priv *priv;
+ int ret;
+
+ priv = container_of(ws, struct iwmct_priv, bus_rescan_worker);
+
+ LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n");
+
+ ret = bus_rescan_devices(priv->func->dev.bus);
+ if (ret < 0)
+ LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
+}
+
+static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
+{
+ switch (msg->hdr.opcode) {
+ case OP_OPR_ALIVE:
+ LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
+ queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
+ break;
+ default:
+ LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
+ msg->hdr.opcode);
+ break;
+ }
+}
+
+
+static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+ struct top_msg *msg;
+
+ msg = (struct top_msg *)buf;
+
+ if (msg->hdr.type != COMM_TYPE_D2H) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP with invalid message type 0x%X\n",
+ msg->hdr.type);
+ return;
+ }
+
+ if (len < sizeof(msg->hdr)) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP is too short for message header "
+ "received %d bytes, expected at least %zd bytes\n",
+ len, sizeof(msg->hdr));
+ return;
+ }
+
+ if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message length (%d bytes) is shorter than "
+ "in header (%d bytes)\n",
+ len, le16_to_cpu(msg->hdr.length));
+ return;
+ }
+
+ switch (msg->hdr.category) {
+ case COMM_CATEGORY_OPERATIONAL:
+ op_top_message(priv, (struct top_msg *)buf);
+ break;
+
+ case COMM_CATEGORY_DEBUG:
+ case COMM_CATEGORY_TESTABILITY:
+ case COMM_CATEGORY_DIAGNOSTICS:
+ iwmct_log_top_message(priv, buf, len);
+ break;
+
+ default:
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP with unknown category 0x%X\n",
+ msg->hdr.category);
+ break;
+ }
+}
+
+int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
+{
+ int ret;
+ u8 *buf;
+
+ LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
+
+ /* add padding to 256 for IWMC */
+ ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
+
+ LOG_HEXDUMP(FW_MSG, cmd, len);
+
+ if (len > FW_HCMD_BLOCK_SIZE) {
+ LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
+ len, FW_HCMD_BLOCK_SIZE);
+ return -1;
+ }
+
+ buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
+ if (!buf) {
+ LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
+ FW_HCMD_BLOCK_SIZE);
+ return -1;
+ }
+
+ memcpy(buf, cmd, len);
+
+ sdio_claim_host(priv->func);
+ ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
+ FW_HCMD_BLOCK_SIZE);
+ sdio_release_host(priv->func);
+
+ kfree(buf);
+ return ret;
+}
+
+int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+ void *src, int count)
+{
+ int ret;
+
+ sdio_claim_host(priv->func);
+ ret = sdio_memcpy_toio(priv->func, addr, src, count);
+ sdio_release_host(priv->func);
+
+ return ret;
+}
+
+static void iwmct_irq_read_worker(struct work_struct *ws)
+{
+ struct iwmct_priv *priv;
+ struct iwmct_work_struct *read_req;
+ __le32 *buf = NULL;
+ int ret;
+ int iosize;
+ u32 barker;
+ bool is_barker;
+
+ priv = container_of(ws, struct iwmct_priv, isr_worker);
+
+ LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
+
+ /* --------------------- Handshake with device -------------------- */
+ sdio_claim_host(priv->func);
+
+ /* all list manipulations have to be protected by
+ * sdio_claim_host/sdio_release_host */
+ if (list_empty(&priv->read_req_list)) {
+ LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
+ goto exit_release;
+ }
+
+ read_req = list_entry(priv->read_req_list.next,
+ struct iwmct_work_struct, list);
+
+ list_del(&read_req->list);
+ iosize = read_req->iosize;
+ kfree(read_req);
+
+ buf = kzalloc(iosize, GFP_KERNEL);
+ if (!buf) {
+ LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
+ goto exit_release;
+ }
+
+ LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
+ iosize, buf, priv->func->num);
+
+ /* read from device */
+ ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
+ if (ret) {
+ LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
+ goto exit_release;
+ }
+
+ LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);
+
+ barker = le32_to_cpu(buf[0]);
+
+ /* Verify whether it's a barker and if not - treat as regular Rx */
+ if (barker == IWMC_BARKER_ACK ||
+ (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) {
+
+ /* Valid Barker is equal on first 4 dwords */
+ is_barker = (buf[1] == buf[0]) &&
+ (buf[2] == buf[0]) &&
+ (buf[3] == buf[0]);
+
+ if (!is_barker) {
+ LOG_WARNING(priv, IRQ,
+ "Potentially inconsistent barker "
+ "%08X_%08X_%08X_%08X\n",
+ le32_to_cpu(buf[0]), le32_to_cpu(buf[1]),
+ le32_to_cpu(buf[2]), le32_to_cpu(buf[3]));
+ }
+ } else {
+ is_barker = false;
+ }
+
+ /* Handle Top CommHub message */
+ if (!is_barker) {
+ sdio_release_host(priv->func);
+ handle_top_message(priv, (u8 *)buf, iosize);
+ goto exit;
+ } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */
+ if (atomic_read(&priv->dev_sync) == 0) {
+ LOG_ERROR(priv, IRQ,
+ "ACK barker arrived out-of-sync\n");
+ goto exit_release;
+ }
+
+ /* Continuing to FW download (after Sync is completed)*/
+ atomic_set(&priv->dev_sync, 0);
+ LOG_INFO(priv, IRQ, "ACK barker arrived "
+ "- starting FW download\n");
+ } else { /* REBOOT barker */
+ LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
+ priv->barker = barker;
+
+ if (barker & BARKER_DNLOAD_SYNC_MSK) {
+ /* Send the same barker back */
+ ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
+ buf, iosize);
+ if (ret) {
+ LOG_ERROR(priv, IRQ,
+ "error %d echoing barker\n", ret);
+ goto exit_release;
+ }
+ LOG_INFO(priv, IRQ, "Echoing barker to device\n");
+ atomic_set(&priv->dev_sync, 1);
+ goto exit_release;
+ }
+
+ /* Continuing to FW download (without Sync) */
+ LOG_INFO(priv, IRQ, "No sync requested "
+ "- starting FW download\n");
+ }
+
+ sdio_release_host(priv->func);
+
+
+ LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
+ LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
+ LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
+ LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
+
+ if (priv->dbg.fw_download)
+ iwmct_fw_load(priv);
+ else
+ LOG_ERROR(priv, IRQ, "FW download not allowed\n");
+
+ goto exit;
+
+exit_release:
+ sdio_release_host(priv->func);
+exit:
+ kfree(buf);
+ LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
+}
+
+static void iwmct_irq(struct sdio_func *func)
+{
+ struct iwmct_priv *priv;
+ int val, ret;
+ int iosize;
+ int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
+ struct iwmct_work_struct *read_req;
+
+ priv = sdio_get_drvdata(func);
+
+ LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
+
+ /* read the function's status register */
+ val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
+
+ LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
+
+ if (!val) {
+ LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
+ goto exit_clear_intr;
+ }
+
+
+ /*
+ * read 2 bytes of the transaction size
+ * IMPORTANT: sdio transaction size has to be read before clearing
+ * sdio interrupt!!!
+ */
+ val = sdio_readb(priv->func, addr++, &ret);
+ iosize = val;
+ val = sdio_readb(priv->func, addr++, &ret);
+ iosize += val << 8;
+
+ LOG_INFO(priv, IRQ, "READ size %d\n", iosize);
+
+ if (iosize == 0) {
+ LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
+ goto exit_clear_intr;
+ }
+
+ /* allocate a work structure to pass iosize to the worker */
+ read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
+ if (!read_req) {
+ LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
+ goto exit_clear_intr;
+ }
+
+ INIT_LIST_HEAD(&read_req->list);
+ read_req->iosize = iosize;
+
+ list_add_tail(&priv->read_req_list, &read_req->list);
+
+ /* clear the function's interrupt request bit (write 1 to clear) */
+ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+
+ queue_work(priv->wq, &priv->isr_worker);
+
+ LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
+
+ return;
+
+exit_clear_intr:
+ /* clear the function's interrupt request bit (write 1 to clear) */
+ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+}
+
+
+static int blocks;
+module_param(blocks, int, 0604);
+MODULE_PARM_DESC(blocks, "max_blocks_to_send");
+
+static int dump;
+module_param(dump, bool, 0604);
+MODULE_PARM_DESC(dump, "dump_hex_content");
+
+static int jump = 1;
+module_param(jump, bool, 0604);
+
+static int direct = 1;
+module_param(direct, bool, 0604);
+
+static int checksum = 1;
+module_param(checksum, bool, 0604);
+
+static int fw_download = 1;
+module_param(fw_download, bool, 0604);
+
+static int block_size = IWMC_SDIO_BLK_SIZE;
+module_param(block_size, int, 0404);
+
+static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
+module_param(download_trans_blks, int, 0604);
+
+static int rubbish_barker;
+module_param(rubbish_barker, bool, 0604);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static int log_level[LOG_SRC_MAX];
+static unsigned int log_level_argc;
+module_param_array(log_level, int, &log_level_argc, 0604);
+MODULE_PARM_DESC(log_level, "log_level");
+
+static int log_level_fw[FW_LOG_SRC_MAX];
+static unsigned int log_level_fw_argc;
+module_param_array(log_level_fw, int, &log_level_fw_argc, 0604);
+MODULE_PARM_DESC(log_level_fw, "log_level_fw");
+#endif
+
+void iwmct_dbg_init_params(struct iwmct_priv *priv)
+{
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+ int i;
+
+ for (i = 0; i < log_level_argc; i++) {
+ dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n",
+ i, log_level[i]);
+ iwmct_log_set_filter((log_level[i] >> 8) & 0xFF,
+ log_level[i] & 0xFF);
+ }
+ for (i = 0; i < log_level_fw_argc; i++) {
+ dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n",
+ i, log_level_fw[i]);
+ iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF,
+ log_level_fw[i] & 0xFF);
+ }
+#endif
+
+ priv->dbg.blocks = blocks;
+ LOG_INFO(priv, INIT, "blocks=%d\n", blocks);
+ priv->dbg.dump = (bool)dump;
+ LOG_INFO(priv, INIT, "dump=%d\n", dump);
+ priv->dbg.jump = (bool)jump;
+ LOG_INFO(priv, INIT, "jump=%d\n", jump);
+ priv->dbg.direct = (bool)direct;
+ LOG_INFO(priv, INIT, "direct=%d\n", direct);
+ priv->dbg.checksum = (bool)checksum;
+ LOG_INFO(priv, INIT, "checksum=%d\n", checksum);
+ priv->dbg.fw_download = (bool)fw_download;
+ LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download);
+ priv->dbg.block_size = block_size;
+ LOG_INFO(priv, INIT, "block_size=%d\n", block_size);
+ priv->dbg.download_trans_blks = download_trans_blks;
+ LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks);
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+static ssize_t show_iwmct_fw_version(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%s\n", priv->dbg.label_fw);
+}
+static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO,
+ show_iwmct_log_level, store_iwmct_log_level);
+static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO,
+ show_iwmct_log_level_fw, store_iwmct_log_level_fw);
+#endif
+
+static struct attribute *iwmct_sysfs_entries[] = {
+ &dev_attr_cc_label_fw.attr,
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+ &dev_attr_log_level.attr,
+ &dev_attr_log_level_fw.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group iwmct_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwmct_sysfs_entries,
+};
+
+
+static int iwmct_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct iwmct_priv *priv;
+ int ret;
+ int val = 1;
+ int addr = IWMC_SDIO_INTR_ENABLE_ADDR;
+
+ dev_dbg(&func->dev, "enter iwmct_probe\n");
+
+ dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
+ jiffies_to_msecs(2147483647), HZ);
+
+ priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&func->dev, "kzalloc error\n");
+ return -ENOMEM;
+ }
+ priv->func = func;
+ sdio_set_drvdata(func, priv);
+
+
+ /* create drivers work queue */
+ priv->wq = create_workqueue(DRV_NAME "_wq");
+ priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
+ INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
+ INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
+
+ init_waitqueue_head(&priv->wait_q);
+
+ sdio_claim_host(func);
+ /* FIXME: Remove after it is fixed in the Boot ROM upgrade */
+ func->enable_timeout = 10;
+
+ /* In our HW, setting the block size also wakes up the boot rom. */
+ ret = sdio_set_block_size(func, priv->dbg.block_size);
+ if (ret) {
+ LOG_ERROR(priv, INIT,
+ "sdio_set_block_size() failure: %d\n", ret);
+ goto error_sdio_enable;
+ }
+
+ ret = sdio_enable_func(func);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret);
+ goto error_sdio_enable;
+ }
+
+ /* init reset and dev_sync states */
+ atomic_set(&priv->reset, 0);
+ atomic_set(&priv->dev_sync, 0);
+
+ /* init read req queue */
+ INIT_LIST_HEAD(&priv->read_req_list);
+
+ /* process configurable parameters */
+ iwmct_dbg_init_params(priv);
+ ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "Failed to register attributes and "
+ "initialize module_params\n");
+ goto error_dev_attrs;
+ }
+
+ iwmct_dbgfs_register(priv, DRV_NAME);
+
+ if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) {
+ LOG_INFO(priv, INIT,
+ "Reducing transaction to 8 blocks = 2K (from %d)\n",
+ priv->dbg.download_trans_blks);
+ priv->dbg.download_trans_blks = 8;
+ }
+ priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size;
+ LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len);
+
+ ret = sdio_claim_irq(func, iwmct_irq);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret);
+ goto error_claim_irq;
+ }
+
+
+ /* Enable function's interrupt */
+ sdio_writeb(priv->func, val, addr, &ret);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "Failure writing to "
+ "Interrupt Enable Register (%d): %d\n", addr, ret);
+ goto error_enable_int;
+ }
+
+ sdio_release_host(func);
+
+ LOG_INFO(priv, INIT, "exit iwmct_probe\n");
+
+ return ret;
+
+error_enable_int:
+ sdio_release_irq(func);
+error_claim_irq:
+ sdio_disable_func(func);
+error_dev_attrs:
+ iwmct_dbgfs_unregister(priv->dbgfs);
+ sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+error_sdio_enable:
+ sdio_release_host(func);
+ return ret;
+}
+
+static void iwmct_remove(struct sdio_func *func)
+{
+ struct iwmct_work_struct *read_req;
+ struct iwmct_priv *priv = sdio_get_drvdata(func);
+
+ priv = sdio_get_drvdata(func);
+
+ LOG_INFO(priv, INIT, "enter\n");
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+
+ /* Safely destroy osc workqueue */
+ destroy_workqueue(priv->bus_rescan_wq);
+ destroy_workqueue(priv->wq);
+
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+ iwmct_dbgfs_unregister(priv->dbgfs);
+ sdio_release_host(func);
+
+ /* free read requests */
+ while (!list_empty(&priv->read_req_list)) {
+ read_req = list_entry(priv->read_req_list.next,
+ struct iwmct_work_struct, list);
+
+ list_del(&read_req->list);
+ kfree(read_req);
+ }
+
+ kfree(priv);
+}
+
+
+static const struct sdio_device_id iwmct_ids[] = {
+ { SDIO_DEVICE(SDIO_INTEL_VENDOR_ID, SDIO_DEVICE_ID_INTEL_IWMC3200TOP)},
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, iwmct_ids);
+
+static struct sdio_driver iwmct_driver = {
+ .probe = iwmct_probe,
+ .remove = iwmct_remove,
+ .name = DRV_NAME,
+ .id_table = iwmct_ids,
+};
+
+static int __init iwmct_init(void)
+{
+ int rc;
+
+ /* Default log filter settings */
+ iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
+ iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
+ iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
+
+ rc = sdio_register_driver(&iwmct_driver);
+
+ return rc;
+}
+
+static void __exit iwmct_exit(void)
+{
+ sdio_unregister_driver(&iwmct_driver);
+}
+
+module_init(iwmct_init);
+module_exit(iwmct_exit);
+
--
1.6.0.6
---------------------------------------------------------------------
Intel Israel (74) Limited
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply related
* [PATCH net-next V2 3/3] i2400m-sdio: select IWMC3200TOP in Kconfig
From: Tomas Winkler @ 2009-10-17 19:09 UTC (permalink / raw)
To: davem, linville, netdev, linux-wireless, linux-mmc
Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
ron.rindjunsky, Tomas Winkler
In-Reply-To: <1255806576-26869-2-git-send-email-tomas.winkler@intel.com>
i2400m-sdio requires iwmc3200top for its operation
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Acked-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/Kconfig | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
index d623b3d..32cb214 100644
--- a/drivers/net/wimax/i2400m/Kconfig
+++ b/drivers/net/wimax/i2400m/Kconfig
@@ -31,6 +31,14 @@ config WIMAX_I2400M_SDIO
If unsure, it is safe to select M (module).
+config WIMAX_IWMC3200_SDIO
+ bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO"
+ depends on WIMAX_I2400M_SDIO
+ select IWMC3200TOP
+ help
+ Select if you have a device based on the Intel Multicom WiMAX
+ Connection 3200 over SDIO.
+
config WIMAX_I2400M_DEBUG_LEVEL
int "WiMAX i2400m debug level"
depends on WIMAX_I2400M
--
1.6.0.6
---------------------------------------------------------------------
Intel Israel (74) Limited
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply related
* [PATCH net-next V2 2/3] iwmc3200wifi: select IWMC3200TOP in Kconfig
From: Tomas Winkler @ 2009-10-17 19:09 UTC (permalink / raw)
To: davem, linville, netdev, linux-wireless, linux-mmc
Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
ron.rindjunsky, Tomas Winkler
In-Reply-To: <1255806576-26869-1-git-send-email-tomas.winkler@intel.com>
iwmc3200wifi requires iwmc3200top for its operation
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Acked-by: Zhu Yi <yi.zhu@intel.com>
---
drivers/net/wireless/iwmc3200wifi/Kconfig | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c25a043..9606b31 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -3,6 +3,7 @@ config IWM
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
select FW_LOADER
+ select IWMC3200TOP
help
The Intel Wireless Multicomm 3200 hardware is a combo
card with GPS, Bluetooth, WiMax and 802.11 radios. It
--
1.6.0.6
---------------------------------------------------------------------
Intel Israel (74) Limited
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply related
* Re: 2.6.32-rc0-git: oops in wireless, iwl3945 related?
From: Pavel Machek @ 2009-10-17 18:33 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-kernel, yi.zhu, reinette.chatre, linux-wireless
In-Reply-To: <1254432469.3959.46.camel@johannes.local>
On Thu 2009-10-01 23:27:49, Johannes Berg wrote:
> On Thu, 2009-10-01 at 23:16 +0200, Johannes Berg wrote:
>
> > > wlan0: Selected IBSS BSSID 02:18:41:de:3f:02 based on configured SSID
> > > wlan0: Trigger new scan to find an IBSS to join
> > > wlan0: Trigger new scan to find an IBSS to join
> > > wlan0: Creating new IBSS network, BSSID f2:d3:80:82:ed:6a
> > > wlan0: Creating new IBSS network, BSSID 52:17:bf:45:d6:9d
> > > skb_over_panic: text:c07b4113 len:130 put:36 head:e4c3edf0
> >
> > This entire log is very odd ... can you reproduce this easily? printk
> > timestamps would be useful.
>
> Kinda looks like a race condition, but it's rather odd. I think there's
> a race condition, so I'm going to submit this patch regardless after
> some testing, but if you want please try the patch below.
Well, the problem is not exactly reproducible... it failed to happen
again. So... thanks and I'll keep my eyes open if it returns.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: iwlwifi 6000 uCode available
From: Maxim Levitsky @ 2009-10-17 16:03 UTC (permalink / raw)
To: reinette chatre
Cc: Gábor Stefanik, linux-wireless@vger.kernel.org,
ipw3945-devel@lists.sourceforge.net
In-Reply-To: <1255735672.21134.635.camel@rc-desk>
On Fri, 2009-10-16 at 16:27 -0700, reinette chatre wrote:
> On Fri, 2009-10-16 at 16:15 -0700, Gábor Stefanik wrote:
> > Are the actual adapters available too, or is this just the
> > release-early-release-often philosophy at work?
>
> You cannot yet purchase a laptop with these cards, but when you can the
> driver will be ready for you.
>
> Reinette
This is the reason I prefer intel to anything.
I even have an intel motherboard in my desktop computer.
Keep up the good work!
Best regards,
Maxim Levitsky
^ permalink raw reply
* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Bartlomiej Zolnierkiewicz @ 2009-10-17 15:19 UTC (permalink / raw)
To: Johannes Berg
Cc: Ivo van Doorn, John Linville, linux-wireless, users,
Alban Browaeys, Benoit PAPILLAULT, Felix Fietkau, Luis Correia,
Mattias Nissler, Mark Asselstine, Xose Vazquez Perez,
linux-kernel
In-Reply-To: <1255792104.3434.2.camel@johannes.local>
On Saturday 17 October 2009 17:08:24 Johannes Berg wrote:
> On Sat, 2009-10-17 at 16:54 +0200, Bartlomiej Zolnierkiewicz wrote:
>
> > I also used the opportunity to take a closer look at this driver and
> > it seems that it needlessly adds around 2 KLOC to kernel by duplicating
> > the common content of rt2800usb.h to rt2800pci.h instead of moving it
> > to the shared header (like it is done in the staging crap drivers):
>
> Tell me you're kidding -- comparing 2k duplicated LOC with a driver that
> ships its own wifi stack?
Why would I be?
1) The patch is submitted to kernel _proper_ not kernel staging so I see
no excuse for duplicating 2-4 KLOC and it should be fixed.
2) The fact that the some staging driver consists in 90% of crap doesn't
mean that it doesn't have some good design ideas.. (i.e. abstracting chipset
registers access in a discussed case)
^ permalink raw reply
* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Johannes Berg @ 2009-10-17 15:08 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Ivo van Doorn, John Linville, linux-wireless, users,
Alban Browaeys, Benoit PAPILLAULT, Felix Fietkau, Luis Correia,
Mattias Nissler, Mark Asselstine, Xose Vazquez Perez,
linux-kernel
In-Reply-To: <200910171654.03344.bzolnier@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 477 bytes --]
On Sat, 2009-10-17 at 16:54 +0200, Bartlomiej Zolnierkiewicz wrote:
> I also used the opportunity to take a closer look at this driver and
> it seems that it needlessly adds around 2 KLOC to kernel by duplicating
> the common content of rt2800usb.h to rt2800pci.h instead of moving it
> to the shared header (like it is done in the staging crap drivers):
Tell me you're kidding -- comparing 2k duplicated LOC with a driver that
ships its own wifi stack?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] rt2x00: Implement support for rt2800pci
From: Bartlomiej Zolnierkiewicz @ 2009-10-17 14:54 UTC (permalink / raw)
To: Ivo van Doorn
Cc: John Linville, linux-wireless, users, Alban Browaeys,
Benoit PAPILLAULT, Felix Fietkau, Luis Correia, Mattias Nissler,
Mark Asselstine, Xose Vazquez Perez, linux-kernel
In-Reply-To: <200910152204.16407.IvDoorn@gmail.com>
[ I somehow missed this one by not being on cc: ]
On Thursday 15 October 2009 22:04:14 Ivo van Doorn wrote:
> Add support for the rt2860/rt3090 chipsets from Ralink.
>
> Includes various patches from a lot of people who helped
> getting this driver into the current shape.
>
> Signed-off-by: Alban Browaeys <prahal@yahoo.com>
> Signed-off-by: Benoit PAPILLAULT <benoit.papillault@free.fr>
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> Signed-off-by: Luis Correia <luis.f.correia@gmail.com>
> Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de>
> Signed-off-by: Mark Asselstine <asselsm@gmail.com>
> Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
> ---
> http://kernel.org/pub/linux/kernel/people/ivd/patches/0003-rt2x00-Implement-support-for-rt2800pci.patch
First let me say that I'm very happy to see this patch finally being
submitted and I appreciate the effort..
(I'll give it a spin on Eee 901 w/ 2.6.32-rc5 sometime later..)
Now to the less happy part..
I also used the opportunity to take a closer look at this driver and
it seems that it needlessly adds around 2 KLOC to kernel by duplicating
the common content of rt2800usb.h to rt2800pci.h instead of moving it
to the shared header (like it is done in the staging crap drivers):
$ wc -l drivers/net/wireless/rt2x00/rt2800usb.h drivers/net/wireless/rt2x00/rt2800pci.h
1951 drivers/net/wireless/rt2x00/rt2800usb.h
1960 drivers/net/wireless/rt2x00/rt2800pci.h
3911 total
$ diff -u drivers/net/wireless/rt2x00/rt2800usb.h drivers/net/wireless/rt2x00/rt2800pci.h|diffstat
rt2800pci.h | 213 +++++++++++++++++++++++++++++++-----------------------------
1 file changed, 111 insertions(+), 102 deletions(-)
Similarly it looks like most of the code between rt2800usb.c and rt2800pci.c
could also be shared (up to another 2 KLOC saved) by adding abstraction layer
for accessing chipset registers over different buses (again like it is done
in staging crap drivers):
$ wc -l drivers/net/wireless/rt2x00/rt2800usb.c drivers/net/wireless/rt2x00/rt2800pci.c
3077 drivers/net/wireless/rt2x00/rt2800usb.c
3323 drivers/net/wireless/rt2x00/rt2800pci.c
6400 total
$ diff -u drivers/net/wireless/rt2x00/rt2800usb.c drivers/net/wireless/rt2x00/rt2800pci.c|diffstat
rt2800pci.c | 2190 +++++++++++++++++++++++++++++++++---------------------------
1 file changed, 1218 insertions(+), 972 deletions(-)
[ for better visualization of issues raised diffs themselves are available at:
http://kernel.org/pub/linux/kernel/people/bart/rt2800/ ]
All in all, the total amount of the kernel code needed for implementing
rt2800pci functionality should 1-2 KLOC instead of the current 5 KLOC.
^ permalink raw reply
* Re: [RFC] WL1251: Very crude EEPROM reading support for the WL1251 driver
From: Kalle Valo @ 2009-10-17 12:54 UTC (permalink / raw)
To: John Willis; +Cc: 'Bob Copeland', linux-wireless
In-Reply-To: <034401ca4f0d$d494a140$7dbde3c0$@Willis@Distant-earth.com>
"John Willis" <John.Willis@Distant-earth.com> writes:
>> Didn't HTC Dream store the NVS file in the main flash memory? AFAIK
>> the EEPROM support in wl1251 needs a separate chip for the EEPROM, so
>> if someone has stored the NVS file to the main flash memory I really
>> doubt that they would still use EEPROM with wl1251. So the NVS file is
>> stored either to somewhere outside wl1251 or to the EEPROM, but not
>> both.
>
> Yep, the NVS on the MSM HTC devices I have seen have been stored in the main
> NAND flash at a given offset outside of the main rootfs 'but' I was sure
> someone had mentioned that the G1 also featured an EEPROM attached to the
> WL1251 as we have on the Pandora.
Ah, ok. Then your patch is really needed for those devices.
> Mea culpa, I could well be wrong on that one. I assumed that the HTC
> platform maintained both as some odd hangover to the Windows CE
> software roots of the platform (it would not be the 1st time ;-)).
Yeah, usually it's like that :)
> I guess that raises another point then, maybe should we look at another
> method of getting the NVS from NAND if the platform gives it's offsets? No
> idea how that would work in a clean way however but something to consider as
> the HTC devices will make up a chunk of the long term userbase.
I think it's better do this in user space, doing this from kernel in a
portable way is too complicated. In earlier discussions the conclusion
has been to use request_firmware() interface and a modified udev
script which retrieves the calibration data from NAND/NOR/whatever and
pushes it to kernel.
To my knowledge nobody hasn't implemented this yet, but I think that's
the way to go. But as always, I'm open for suggestions.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH] mac80211: fix SME warning by removing stale BSS upon assoc failure
From: Luis R. Rodriguez @ 2009-10-17 9:44 UTC (permalink / raw)
To: Johannes Berg
Cc: John W. Linville, Luis Rodriguez, linux-wireless@vger.kernel.org,
ic.felix@gmail.com
In-Reply-To: <1255739280.4095.343.camel@johannes.local>
On Fri, Oct 16, 2009 at 5:28 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Fri, 2009-10-16 at 14:20 -0400, John W. Linville wrote:
>> On Fri, Oct 16, 2009 at 06:31:32PM +0900, Johannes Berg wrote:
>> > On Wed, 2009-10-14 at 16:35 -0700, Luis R. Rodriguez wrote:
>> >
>> > > Well sure, but why do we want to keep the authentication present if
>> > > association failed? And as a matter of fact it lingers there forever.
>> > > Is that desired behaviour?
>> >
>> > Yes, well, the SME is supposed to clean it up or try the association
>> > again (possibly with different parameters in the IEs, e.g. different WPA
>> > settings). The cfg80211 SME certainly does so (it deauthenticates).
>> >
>> > > > > +++ b/net/mac80211/mlme.c
>> > > > > @@ -1463,11 +1463,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
>> > > > > if (status_code != WLAN_STATUS_SUCCESS) {
>> > > > > printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
>> > > > > sdata->dev->name, status_code);
>> > > > > list_del(&wk->list);
>> > > > > kfree(wk);
>> > > > > - return RX_MGMT_CFG80211_ASSOC;
>> > > > > + return RX_MGMT_CFG80211_DEAUTH;
>> > > >
>> > > > I'm sure this is correct. Maybe cfg80211 doesn't react properly to
>> > > > getting an assoc frame with non-zero status?
>> > >
>> > > I see, will have to take a look when I get a chance then, not now though.
>> >
>> > > Actually can you elaborate a little on the logic here as to why
>> > > we want to issue an association command with non-zero status to
>> > > cfg80211 instead of just knocking off the current authentication
>> > > and killing the BSS?
>> >
>> > Is the above sufficient? Btw, please don't talk about "killing the BSS",
>> > you're not talking about a BSS struct but rather one of the mlme work
>> > structs.
>>
>> So, should this patch be dropped? It is currently in w-t...
>
> Yes.
This issue is also present on 2.6.32 I believe, I am curious if we'll
come up with something as small as this for a fix there.
Luis
Luis
^ permalink raw reply
* Re: [PATCH] mac80211: fix SME warning by removing stale BSS upon assoc failure
From: Luis R. Rodriguez @ 2009-10-17 9:40 UTC (permalink / raw)
To: Johannes Berg
Cc: Luis Rodriguez, linville@tuxdriver.com,
linux-wireless@vger.kernel.org, ic.felix@gmail.com
In-Reply-To: <1255685492.4095.309.camel@johannes.local>
On Fri, Oct 16, 2009 at 2:31 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Wed, 2009-10-14 at 16:35 -0700, Luis R. Rodriguez wrote:
>
>> Well sure, but why do we want to keep the authentication present if
>> association failed? And as a matter of fact it lingers there forever.
>> Is that desired behaviour?
>
> Yes, well, the SME is supposed to clean it up or try the association
> again (possibly with different parameters in the IEs, e.g. different WPA
> settings). The cfg80211 SME certainly does so (it deauthenticates).
Ok so that's what's busted then it seems.
Luis
^ permalink raw reply
* RE: [PATCH 14/16] iwmc3200wifi: Support unexpected reboot barker
From: Zhu, Yi @ 2009-10-17 8:18 UTC (permalink / raw)
To: Tomas Winkler
Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org,
Samuel Ortiz
In-Reply-To: <1ba2fa240910161506n6c519398h7795656309bffd93@mail.gmail.com>
SGkgVG9tYXMhDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogVG9tYXMg
V2lua2xlciBbbWFpbHRvOnRvbWFzd0BnbWFpbC5jb21dDQo+IFNlbnQ6IDIwMDnE6jEw1MIxN8jV
IDY6MDcNCj4gVG86IFpodSwgWWkNCj4gQ2M6IGxpbnZpbGxlQHR1eGRyaXZlci5jb207IGxpbnV4
LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZzsgU2FtdWVsIE9ydGl6DQo+IFN1YmplY3Q6IFJlOiBb
UEFUQ0ggMTQvMTZdIGl3bWMzMjAwd2lmaTogU3VwcG9ydCB1bmV4cGVjdGVkIHJlYm9vdCBiYXJr
ZXINCj4gDQo+IE9uIEZyaSwgT2N0IDE2LCAyMDA5IGF0IDc6MTggQU0sIFpodSBZaSA8eWkuemh1
QGludGVsLmNvbT4gd3JvdGU6DQo+ID4gRnJvbTogU2FtdWVsIE9ydGl6IDxzYW1lb0BsaW51eC5p
bnRlbC5jb20+DQo+ID4NCj4gPiBXZSBjYW4gcmVjZWl2ZSB1bmV4cGVjdGVkIHJlYm9vdCBiYXJr
ZXIgYXQgYW55IHRpbWUsIGFuZCB3ZSdyZSBzdXBwb3NlZCB0bw0KPiA+IHJlc2V0IHRoZSB3aG9s
ZSBkZXZpY2UgdGhlbi4NCj4gDQo+IFdoYXQgZG8geW8gbWVhbiwgYnkgd2hvbGUgZGV2aWNlID8g
QW5kIHdobyBpcyB3ZSBpbiB0aGlzIGNvbnRleHQ/DQoNCldlIGFyZSB0YWxraW5nIGZyb20gdGhl
IHdpZmkgZHJpdmVyJ3MgcGVyc3BlY3RpdmUuIFRoZSBjb2RlIGlzIG9yaWdpbmFsbHkgdXNlZCBv
bmx5IGZvciBTViB0ZXN0aW5nLiBUaGVuIHdlIGZpbmQgaXQgbWlnaHQgYmUgdXNlZnVsIGluIHRo
ZSBnZW5lcmFsIGNhc2UuIFN1cHBvc2UgdGhlIGRyaXZlciBnZXQgYSBSRUJPT1RfQkFSS0VSIGZy
b20gdGhlIGNhcmQgKGZvciB3aGF0ZXZlciByZWFzb24pLCBpcyByZXNldHRpbmcgdGhlIGRldmlj
ZSB0aGUgY29ycmVjdCBiZWhhdmlvcj8NCg0KVGhhbmtzLA0KLXlpDQo=
^ permalink raw reply
* Re: [RFC] WL1251: Very crude EEPROM reading support for the WL1251 driver
From: Kalle Valo @ 2009-10-17 6:16 UTC (permalink / raw)
To: Bob Copeland; +Cc: John Willis, linux-wireless
In-Reply-To: <20091016115909.GB341@hash.localnet>
Bob Copeland <me@bobcopeland.com> writes:
> On Thu, Oct 15, 2009 at 04:51:49PM +0100, John Willis wrote:
>> The patches are not yet complete but they do work for me (tm) so I would be
>> very interested in seeing if these hacks also allow us to use the EEPROM on
>> the HTC Dream (Bob, can you try that?, no rush however).
>
> Yeah, I'll give it a spin. It'd be really nice if people don't need to
> use the NVS file.
Didn't HTC Dream store the NVS file in the main flash memory? AFAIK
the EEPROM support in wl1251 needs a separate chip for the EEPROM, so
if someone has stored the NVS file to the main flash memory I really
doubt that they would still use EEPROM with wl1251. So the NVS file is
stored either to somewhere outside wl1251 or to the EEPROM, but not
both.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH] wl1251: rename spi device to wl1251
From: Kalle Valo @ 2009-10-17 5:59 UTC (permalink / raw)
To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1255686697.4095.324.camel@johannes.local>
Johannes Berg <johannes@sipsolutions.net> writes:
>> static struct spi_driver wl1251_spi_driver = {
>> .driver = {
>> - .name = "wl12xx",
>> + .name = "wl1251",
>> .bus = &spi_bus_type,
>> .owner = THIS_MODULE,
>
> IIRC there's a preprocessor symbol for the module name (MODULE_NAME?)
Yes, there is DRIVER_NAME macro. I'll send a new patch on top of this
one. Thanks.
--
Kalle Valo
^ permalink raw reply
* Re: [Ipw2100-devel] 2.6.32-rc4 ipw2200: oops on missing firmware
From: Ferenc Wagner @ 2009-10-17 2:13 UTC (permalink / raw)
To: Zhu Yi
Cc: ipw2100-devel@lists.sourceforge.net,
linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1255589428.3719.465.camel@debian>
Zhu Yi <yi.zhu@intel.com> writes:
> OK. The rfkill device is removed without being added before! The root
> cause is, for non-monitor interfaces, the syntax for
> alloc_ieee80211/free_80211 is wrong. Because alloc_ieee80211 only
> creates (wiphy_new) a wiphy, but free_80211() does wiphy_unregister()
> also. This is only correct when the later wiphy_register() is called
> successfully, which apparently is not the case for your fw doesn't exist
> one. Please see if this patch fix the problem.
I confirm that your patch fixes the problem for me. With it, the
kernel doesn't oops and modprobe isn't killed after the firmware load
timeout. Without firmware, the loaded module is nonfunctional, as
expected.
--
Thanks,
Feri.
^ permalink raw reply
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