* [PATCH -next] libertas: depends on CFG80211
From: Randy Dunlap @ 2009-10-09 23:17 UTC (permalink / raw)
To: Stephen Rothwell, linux-wireless, Dan Williams
Cc: linux-next, LKML, libertas-dev
In-Reply-To: <20091009190654.741eeffd.sfr@canb.auug.org.au>
From: Randy Dunlap <randy.dunlap@oracle.com>
libertas uses CFG80211 functions so it should depend on that symbol.
drivers/built-in.o: In function `lbs_cfg_free':
(.text+0x9ca93): undefined reference to `wiphy_unregister'
drivers/built-in.o: In function `lbs_cfg_free':
(.text+0x9ca9a): undefined reference to `wiphy_free'
drivers/built-in.o: In function `lbs_cfg_register':
(.text+0x9cb45): undefined reference to `wiphy_register'
drivers/built-in.o: In function `lbs_cfg_alloc':
(.text+0x9cc64): undefined reference to `wiphy_new'
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
---
drivers/net/wireless/libertas/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- linux-next-20091009.orig/drivers/net/wireless/libertas/Kconfig
+++ linux-next-20091009/drivers/net/wireless/libertas/Kconfig
@@ -1,6 +1,6 @@
config LIBERTAS
tristate "Marvell 8xxx Libertas WLAN driver support"
- depends on WLAN_80211
+ depends on WLAN_80211 && CFG80211
select WIRELESS_EXT
select WEXT_SPY
select LIB80211
^ permalink raw reply
* mmotm 2009-10-09-01-07 - iwl3945 fails to do firmware load request
From: Valdis.Kletnieks @ 2009-10-10 0:12 UTC (permalink / raw)
To: Andrew Morton, Zhu Yi, John W. Linville; +Cc: linux-kernel, linux-wireless
In-Reply-To: <200910090830.n998Ubvv020464@imap1.linux-foundation.org>
[-- Attachment #1: Type: text/plain, Size: 2644 bytes --]
On Fri, 09 Oct 2009 01:07:49 PDT, akpm@linux-foundation.org said:
> The mm-of-the-moment snapshot 2009-10-09-01-07 has been uploaded to
>
> http://userweb.kernel.org/~akpm/mmotm/
Broke my iwl3945 wireless card:
Good (2.6.31-mmotm0917)
Oct 8 09:55:33 turing-police kernel: [ 0.809101] iwl3945: Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux, 1.2.26ks
Oct 8 09:55:33 turing-police kernel: [ 0.809106] iwl3945: Copyright(c) 2003-2009 Intel Corporation
Oct 8 09:55:33 turing-police kernel: [ 0.809201] iwl3945 0000:0c:00.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
Oct 8 09:55:33 turing-police kernel: [ 0.879463] iwl3945 0000:0c:00.0: Tunable channels: 11 802.11bg, 13 802.11a channels
Oct 8 09:55:33 turing-police kernel: [ 0.879466] iwl3945 0000:0c:00.0: Detected Intel Wireless WiFi Link 3945ABG
...
Oct 8 09:55:35 turing-police kernel: [ 31.599751] iwl3945 0000:0c:00.0: firmware: requesting iwlwifi-3945-2.ucode
Oct 8 09:55:35 turing-police kernel: [ 31.697046] iwl3945 0000:0c:00.0: loaded firmware version 15.28.2.8
Oct 8 09:55:35 turing-police kernel: [ 31.777214] Registered led device: iwl-phy0::radio
Oct 8 09:55:35 turing-police kernel: [ 31.777430] Registered led device: iwl-phy0::assoc
Oct 8 09:55:35 turing-police kernel: [ 31.777545] Registered led device: iwl-phy0::RX
Oct 8 09:55:35 turing-police kernel: [ 31.777676] Registered led device: iwl-phy0::TX
Oct 8 09:55:35 turing-police kernel: [ 31.789446] ADDRCONF(NETDEV_UP): wlan0: link is not ready
(and then wpa-supplicant is able to bring the card up when it finally gets launched by initscripts)
Bad 2.6.32-rc3-mmotm1009:
Oct 9 13:50:19 turing-police kernel: [ 0.931788] iwl3945: Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux, 1.2.26ks
Oct 9 13:50:19 turing-police kernel: [ 0.944678] iwl3945: Copyright(c) 2003-2009 Intel Corporation
Oct 9 13:50:19 turing-police kernel: [ 0.957831] iwl3945 0000:0c:00.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
Oct 9 13:50:19 turing-police kernel: [ 1.038946] iwl3945 0000:0c:00.0: Tunable channels: 11 802.11bg, 13 802.11a channels
Oct 9 13:50:19 turing-police kernel: [ 1.038950] iwl3945 0000:0c:00.0: Detected Intel Wireless WiFi Link 3945ABG
We never see the firmware load request, and of course everything goes
pear-shaped after that doesn't happen....
Kernel is built with:
% zgrep -i iwl /proc/config.gz
CONFIG_IWLWIFI=y
CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT=y
# CONFIG_IWLWIFI_DEBUG is not set
CONFIG_IWLWIFI_DEVICE_TRACING=y
# CONFIG_IWLAGN is not set
CONFIG_IWL3945=y
CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y
[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply
* Re: mmotm 2009-10-09-01-07 - iwl3945 fails to do firmware load request
From: Zhu Yi @ 2009-10-10 0:42 UTC (permalink / raw)
To: Valdis.Kletnieks@vt.edu
Cc: Andrew Morton, John W. Linville, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org
In-Reply-To: <16108.1255133561@turing-police.cc.vt.edu>
On Sat, 2009-10-10 at 08:12 +0800, Valdis.Kletnieks@vt.edu wrote:
> On Fri, 09 Oct 2009 01:07:49 PDT, akpm@linux-foundation.org said:
> > The mm-of-the-moment snapshot 2009-10-09-01-07 has been uploaded to
> >
> > http://userweb.kernel.org/~akpm/mmotm/
>
> Broke my iwl3945 wireless card:
>
> Good (2.6.31-mmotm0917)
> Oct 8 09:55:33 turing-police kernel: [ 0.809101] iwl3945: Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux, 1.2.26ks
> Oct 8 09:55:33 turing-police kernel: [ 0.809106] iwl3945: Copyright(c) 2003-2009 Intel Corporation
> Oct 8 09:55:33 turing-police kernel: [ 0.809201] iwl3945 0000:0c:00.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
> Oct 8 09:55:33 turing-police kernel: [ 0.879463] iwl3945 0000:0c:00.0: Tunable channels: 11 802.11bg, 13 802.11a channels
> Oct 8 09:55:33 turing-police kernel: [ 0.879466] iwl3945 0000:0c:00.0: Detected Intel Wireless WiFi Link 3945ABG
> ...
> Oct 8 09:55:35 turing-police kernel: [ 31.599751] iwl3945 0000:0c:00.0: firmware: requesting iwlwifi-3945-2.ucode
> Oct 8 09:55:35 turing-police kernel: [ 31.697046] iwl3945 0000:0c:00.0: loaded firmware version 15.28.2.8
> Oct 8 09:55:35 turing-police kernel: [ 31.777214] Registered led device: iwl-phy0::radio
> Oct 8 09:55:35 turing-police kernel: [ 31.777430] Registered led device: iwl-phy0::assoc
> Oct 8 09:55:35 turing-police kernel: [ 31.777545] Registered led device: iwl-phy0::RX
> Oct 8 09:55:35 turing-police kernel: [ 31.777676] Registered led device: iwl-phy0::TX
> Oct 8 09:55:35 turing-police kernel: [ 31.789446] ADDRCONF(NETDEV_UP): wlan0: link is not ready
> (and then wpa-supplicant is able to bring the card up when it finally gets launched by initscripts)
>
> Bad 2.6.32-rc3-mmotm1009:
>
> Oct 9 13:50:19 turing-police kernel: [ 0.931788] iwl3945: Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux, 1.2.26ks
> Oct 9 13:50:19 turing-police kernel: [ 0.944678] iwl3945: Copyright(c) 2003-2009 Intel Corporation
> Oct 9 13:50:19 turing-police kernel: [ 0.957831] iwl3945 0000:0c:00.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
> Oct 9 13:50:19 turing-police kernel: [ 1.038946] iwl3945 0000:0c:00.0: Tunable channels: 11 802.11bg, 13 802.11a channels
> Oct 9 13:50:19 turing-police kernel: [ 1.038950] iwl3945 0000:0c:00.0: Detected Intel Wireless WiFi Link 3945ABG
>
> We never see the firmware load request, and of course everything goes
> pear-shaped after that doesn't happen....
The firmware loading happens when the user space brings the interface
up. Can you check NM is running for the bad case?
Thanks,
-yi
^ permalink raw reply
* Re: deauthentication and disassociation nl80211 commands
From: Maxim Levitsky @ 2009-10-10 3:45 UTC (permalink / raw)
To: hostap@lists.shmoo.com; +Cc: linux-wireless
In-Reply-To: <1254708707.24430.68.camel@maxim-laptop>
On Mon, 2009-10-05 at 04:11 +0200, Maxim Levitsky wrote:
> Here I want to ask and summarize problems we found in thread
> 'driver_nl80211 broken again'
>
>
> First of all it it known that lifetime of connection to access point is
> typically:
>
> authentication request/response
> association request/response
>
> EAPOL 4 way handshake (for WPA)
>
> <session>
>
> disassociation
> deauthentication
>
> Today kernel explicitly requests the driver to perform both
> disassociation and deauthentication in that order.
> It is also possible to do disassociation and then association, skipping
> the authentication step.
>
> However, currently wpa_supplicant assumes that once it called
> wpa_drv_disassociate it can again start the complete connect sequence
> from the authentication.
>
> In fact I have carefully studied the code and found that calls to
> wpa_supplicant_deauthenticate (which is the only user of
> wpa_drv_deauthenticate) only happen at deinitialization of wireless
> interface and when wpa_supplicant really has to do it, that is if there
> is a failure (mic failure for example).
>
> My hacky patch that was rejected on the grounds that it is not right to
> introduce the driver dependent behavior might actually be the correct
> solution. It just makes the wpa_supplicant_disassociate do both
> disassociation and deauthentication, as was always assumed by the
> wpa_supplicant core.
>
>
> Or kernel should became smarter and do the work for wpa_supplicant.
>
> In this case it should work like that:
>
> If mac80211 is already authenticated to the AP that was requested, it
> should just return success.
> However currently (and I was told that this is feature, not a bug)
> mac80211 would flatly refuse to do any scanning while it is in
> authenticated but not associated state.
>
> If it isn't authenticated to new AP then, new authentication should be
> made.
> (and old one can be kept, but removed after a timeout)
>
>
> And the last question.
> When do you plan to switch officially the wpa_supplicant to
> driver_nl80211?
>
> Currently it has this issue, and another issue that it (nl80211) reports
> signal levels in another format that NetworkManager doesn't understand.
>
> Other that that it is faster, and especially it allows me to bring
> network up, when I press rfkill button within 4 seconds or less.
>
>
> Best regards,
> Maxim Levitsky
>
Nobody uses driver_nl80211 but me?
Best regards,
Maxim Levitsky
^ permalink raw reply
* Re: mmotm 2009-10-09-01-07 uploaded (b43)
From: Larry Finger @ 2009-10-10 3:55 UTC (permalink / raw)
To: Randy Dunlap; +Cc: akpm, linux-wireless, linux-kernel
In-Reply-To: <20091009154732.af708827.rdunlap@xenotime.net>
On 10/09/2009 05:47 PM, Randy Dunlap wrote:
>
> In file included from mmotm-2009-1009-0107/drivers/net/wireless/b43/b43.h:12,
> from mmotm-2009-1009-0107/drivers/net/wireless/b43/main.c:47:
These warnings occur because CONFIG_B43_LEDS is not set, probably
because CONFIG_MAC80211_LEDS is not set. See the patch in
http://marc.info/?l=linux-wireless&m=125509895406304&w=2.
Larry
^ permalink raw reply
* Re: mmotm 2009-10-09-01-07 - iwl3945 fails to do firmware load request
From: Valdis.Kletnieks @ 2009-10-10 5:22 UTC (permalink / raw)
To: Zhu Yi
Cc: Andrew Morton, John W. Linville, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org
In-Reply-To: <1255135355.3719.22.camel@debian>
[-- Attachment #1: Type: text/plain, Size: 618 bytes --]
On Sat, 10 Oct 2009 08:42:35 +0800, Zhu Yi said:
> The firmware loading happens when the user space brings the interface
> up. Can you check NM is running for the bad case?
I'm not using NM, because I've never figured out how to get it to DTRT for
my network config, so I run wpa_supplicant directly. It's looking like
a bad update to dbus was the actual root cause.
(Did I mention how I loath dbus? Or at least the fact that if it breaks,
everything from wireless to pulseaudio immediately craps out too. That and
'hald' are my two favorite "only on this laptop because stuff refuses to
work without them"....)
[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Tomas Winkler @ 2009-10-10 9:38 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: <1253662724-16497-2-git-send-email-tomas.winkler@intel.com>
On Wed, Sep 23, 2009 at 1:38 AM, Tomas Winkler <tomas.winkler@intel.com> wrote:
> 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>
Dave,
are you going to merge this one?
iwmc3200wifi and i200m-sdio which are already merged are usless without it
Thanks
Tomas
^ permalink raw reply
* Re: Ath5k data aborts
From: Nick Kossifidis @ 2009-10-10 10:56 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: linux-wireless, ath5k-devel, netdev
In-Reply-To: <m3tyy8fkda.fsf@intrepid.localdomain>
2009/10/9 Krzysztof Halasa <khc@pm.waw.pl>:
> Hi,
>
> I have done a small investigation. IXP425 (ARM) in big-endian mode,
> EABI, mini-PCI atk5k wifi card, hostapd.
>
> Atheros Communications Inc. Atheros AR5001X+ Wireless Network Adapter (rev 01)
> Subsystem: Wistron NeWeb Corp. CM9 Wireless a/b/g MiniPCI Adapter
> 168c:0013 subsystem 185f:1012
>
>
> Results:
> Bad mode in data abort handler detected
> Internal error: Oops - bad mode: 0 [#1]
> LR is at ath5k_beacon_config+0x150/0x1d4 [ath5k]
>
> This means the PCI device didn't respond on the bus or something
> like that. Obviously the card is then unusable and the system needs to
> be restarted.
>
> Bisecting (I had to modify the procedure a bit since it only started to
> show up after other unrelated code was merged) shows the guilty commit:
> e8f055f0c3ba226ca599c14c2e5fe829f6f57cbb (ath5k: Update reset code).
>
> The problem exists with 2.6.30, 2.6.31 and current Linus' tree.
>
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> ----------------------------------------------
> 2.6.30 appears to be fixed by:
>
> --- a/drivers/net/wireless/ath5k/reset.c
> +++ b/drivers/net/wireless/ath5k/reset.c
> @@ -476,7 +476,7 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
> (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
> ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
> ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
> - ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
> + ath5k_hw_reg_write(ah, 0x0C, AR5K_PHY_SCLOCK);
> ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
> AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
> AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
> @@ -490,8 +490,10 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
> }
>
> /* Enable sleep clock operation */
> +#if 0
> AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
> AR5K_PCICFG_SLEEP_CLOCK_EN);
> +#endif
>
> } else {
>
>
>
> The AR5K_PHY_SCLOCK brings the old value (before the commit in question)
> back, I have no idea what is it. Leaving the new value causes the second
> run of hostapd to make the driver fail, the chip seems to not respond.
> It seems the value itself may be correct (as it works with 2.6.31+) but
> there is some additional bug fixed after 2.6.30, gitk show several
> candidate patches for this.
>
>
> Only disabling AR5K_PCICFG write makes the data abort go away.
>
> ----------------------------------------------
> 2.6.31 and Linus-current only need the AR5K_PCICFG change:
>
> --- a/drivers/net/wireless/ath/ath5k/reset.c
> +++ b/drivers/net/wireless/ath/ath5k/reset.c
> @@ -489,9 +489,10 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
> }
>
> /* Enable sleep clock operation */
> +#if 0
> AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
> AR5K_PCICFG_SLEEP_CLOCK_EN);
> -
> +#endif
> } else {
>
> /* Disable sleep clock operation and
>
>
> The question is, obviously, how to fix that for good. I can test the
> result.
Interesting, can you provide us with an eeprom info dump from your
card (using ath_info tool from madwifi svn) ?
It seems we need to skip sleep clock operation in your case.
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Marcel Holtmann @ 2009-10-10 11:01 UTC (permalink / raw)
To: Tomas Winkler
Cc: davem, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <1253662724-16497-2-git-send-email-tomas.winkler@intel.com>
Hi Tomas,
> 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>
> ---
> drivers/misc/Kconfig | 1 +
> drivers/misc/Makefile | 1 +
> drivers/misc/iwmc3200top/Kconfig | 20 +
> drivers/misc/iwmc3200top/Makefile | 29 ++
> drivers/misc/iwmc3200top/debugfs.c | 145 +++++++
> drivers/misc/iwmc3200top/debugfs.h | 61 +++
> drivers/misc/iwmc3200top/fw-download.c | 359 ++++++++++++++++
> drivers/misc/iwmc3200top/fw-msg.h | 113 +++++
> drivers/misc/iwmc3200top/iwmc3200top.h | 202 +++++++++
> drivers/misc/iwmc3200top/log.c | 339 +++++++++++++++
> drivers/misc/iwmc3200top/log.h | 158 +++++++
> drivers/misc/iwmc3200top/main.c | 702 ++++++++++++++++++++++++++++++++
> 12 files changed, 2130 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 68ab39d..6f85b43 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -236,5 +236,6 @@ config ISL29003
> 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 36f733c..97f5303 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -20,5 +20,6 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
> obj-$(CONFIG_HP_ILO) += hpilo.o
> obj-$(CONFIG_ISL29003) += isl29003.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..a531f6c
> --- /dev/null
> +++ b/drivers/misc/iwmc3200top/debugfs.c
> @@ -0,0 +1,145 @@
> +/*
> + * 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 "iwmc3200top.h"
> +#include "log.h"
> +#include "fw-msg.h"
> +#include "debugfs.h"
> +
> +/* Constants definition */
> +#define HEXADECIMAL_RADIX 16
> +
> +/* Functions definition */
> +
> +
> +/* Debugfs macros */
> +#define DEBUGFS_ADD_DIR(name, parent) do { \
> + dbgfs->dir_##name = debugfs_create_dir(#name, parent); \
> + if (!(dbgfs->dir_##name)) \
> + goto err; \
> +} while (0)
> +
> +#define DEBUGFS_ADD_FILE(name, parent) do { \
> + dbgfs->dbgfs_##parent##_files.file_##name = \
> + debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
> + &iwmct_dbgfs_##name##_ops); \
> + if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
> + goto err; \
> +} while (0)
> +
> +#define DEBUGFS_REMOVE(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 */
> +
> +/* Debugfs registration functions */
> +
> +/*
> + * Create the debugfs files and directories
> + *
> + */
so for me the whole debug infrastructure is way too much overhead for
what this driver has to achieve. What is the benefit of having all these
debugfs support. What is it trying to achieve?
Also all these macros really obfuscate the code for no real benefit. If
you wanna keep debugfs support, then just use the functions directly.
They are not that complicated that an extra abstraction layer is needed.
> +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));
> + goto err;
> + }
> +
> + 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");
> + goto err;
> + }
> +
> +
> +err:
> + return;
> +}
goto err. Seriously. Just call return in the error case. And also there
is a memory leak if the debugfs_create_dir fails.
> +/**
> + * Remove the debugfs files and directories
> + *
> + */
> +void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
> +{
> + if (!dbgfs)
> + return;
> +
> +
> + DEBUGFS_REMOVE(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..24b1369
> --- /dev/null
> +++ b/drivers/misc/iwmc3200top/debugfs.h
> @@ -0,0 +1,61 @@
> +/*
> + * 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
> +
> +#include <linux/debugfs.h>
> +
> +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 is empty if CONFIG_IWMC3200TOP_DEBUGFS is not defined */
> +struct iwmct_debugfs {
> +};
If struct iwmct_debugfs is never referenced directly then a simple
forward struct imwct_debugfs; declaration is good enough.
> +
> +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);
This logging is overkill. Can we just hide this via pr_debug and then
use just simply dynamic_printk support.
> +
> + 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));
The access to file and parser->file. One with unaligned access and the
other with, looks wrong. And it looks way to complicated.
Can we just not have a proper __le32 type of parser->file to begin with.
> +
> + 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;
This if statement is unreadable. This indentation gives me a headache.
Also this function better return bool and not int.
> + } 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..59e4b7a
> --- /dev/null
> +++ b/drivers/misc/iwmc3200top/iwmc3200top.h
> @@ -0,0 +1,202 @@
> +/*
> + * 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__
> +
> +#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_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..96b5e4a
> --- /dev/null
> +++ b/drivers/misc/iwmc3200top/log.c
> @@ -0,0 +1,339 @@
> +/*
> + * 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 = d->driver_data;
> + char *str_buf;
> + int buf_size;
> + ssize_t ret = -EAGAIN;
> +
> + 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);
> + goto exit;
> + }
> +
> + if (log_get_filter_str(str_buf, buf_size) < 0)
> + 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 = d->driver_data;
> + char *token, *str_buf = NULL;
> + long val;
> + u8 src, mask;
> +
> + if (!count)
> + goto err;
> +
> + str_buf = kzalloc(count, GFP_KERNEL);
> + if (!str_buf) {
> + LOG_ERROR(priv, DEBUGFS,
> + "failed to allocate %zd bytes\n", count);
> + goto err;
> + }
> +
> + 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);
> + goto err;
> + }
> +
> + mask = val & 0xFF;
> + src = (val & 0XFF00) >> 8;
> + iwmct_log_set_filter(src, mask);
> + }
> +
> + kfree(str_buf);
> + return count;
> +
> +err:
> + kfree(str_buf);
> + return -EAGAIN;
> +}
> +
> +ssize_t show_iwmct_log_level_fw(struct device *d,
> + struct device_attribute *attr, char *buf)
> +{
> + struct iwmct_priv *priv = d->driver_data;
> + char *str_buf;
> + int buf_size;
> + ssize_t ret = -EAGAIN;
> +
> + 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);
> + goto exit;
> + }
> +
> + if (log_get_fw_filter_str(str_buf, buf_size) < 0)
> + 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 = d->driver_data;
> + char *token, *str_buf = NULL;
> + long val;
> + u8 src, mask;
> + struct top_msg cmd;
> + u16 cmdlen = 0;
> + int i, rc;
> +
> + if (!count)
> + goto err;
> +
> + str_buf = kzalloc(count, GFP_KERNEL);
> + if (!str_buf) {
> + LOG_ERROR(priv, DEBUGFS,
> + "failed to allocate %zd bytes\n", count);
> + goto err;
> + }
> +
> + 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);
> + goto err;
> + }
> +
> + 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));
> +
> + rc = iwmct_send_hcmd(priv, (u8 *) &cmd, cmdlen);
> + if (rc) {
> + LOG_ERROR(priv, DEBUGFS,
> + "Failed to send %d bytes of fwcmd, rc=%d\n",
> + cmdlen, rc);
> + goto err;
> + } else
> + LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
> +
> + kfree(str_buf);
> + return count;
> +
> +err:
> + kfree(str_buf);
> + return -EAGAIN;
> +}
> +
> 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__ */
Seriously. Please just use dynamic_printk and lets remove all this log
infrastructure. It is way too much overhead for too little benefit.
> diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
> new file mode 100644
> index 0000000..09f8d06
> --- /dev/null
> +++ b/drivers/misc/iwmc3200top/main.c
> @@ -0,0 +1,702 @@
> +/*
> + * 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/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 ""
> +#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);
> +
> +
> +#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, val, i;
> + int iosize;
> + u32 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]);
> + if (barker != IWMC_BARKER_ACK &&
> + (barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
> + /* Handle Top Commhub message.
> + * Current handling - treat all message as
> + * logger messages and print the context as a string. */
> + sdio_release_host(priv->func);
> + handle_top_message(priv, (u8 *)buf, iosize);
> + goto exit;
> + }
> +
> + /* verify basic barker sanity */
> + for (i = 1; i < 4; i++)
> + if (buf[i] != buf[0]) {
> + LOG_ERROR(priv, IRQ, "Corrupted barker,"
> + "buf[%d]=%x buf[0]=%x\n",
> + i, buf[i], buf[0]);
> + goto exit_release;
> + }
> +
> + val = atomic_read(&priv->dev_sync);
> +
> + switch (val) {
> + case 0:
> + /* we expect to recieve REBOOT BARKER */
> + if ((barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
> + LOG_ERROR(priv, IRQ, "Expecting for reboot barker %x,"
> + "but got %x\n",
> + IWMC_BARKER_REBOOT,
> + (barker & BARKER_DNLOAD_BARKER_MSK));
> + goto exit_release;
> + }
> +
> + 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_inc(&priv->dev_sync);
> + goto exit_release;
> + }
> + break;
> +
> + case 1:
> + /* we expect to recieve ACK BARKER */
> + if (barker != IWMC_BARKER_ACK) {
> + LOG_INFO(priv, IRQ, "Expecting for ACK barker[%x],"
> + "got this instead %x\n",
> + IWMC_BARKER_ACK, barker);
> + goto exit_release;
> + }
> + kfree(buf);
> + atomic_set(&priv->dev_sync, 0);
> + atomic_set(&priv->reset, 0);
> + break;
> +
> + default:
> + LOG_INFO(priv, IRQ, "Wrong dev_sync %d\n", val);
> + break;
> + }
> +
> + 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");
> +
> + return;
> +
> +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);
Most of them are missing descriptions. And do we really need them? What
cases are they trying to work around?
> +
> +#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)
> +{
> + return sprintf(buf, "%s\n",
> + ((struct iwmct_priv *)d->driver_data)->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
First module parameters and now device attributes. Why?
> +
> +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_info(&func->dev, "enter iwmct_probe\n");
> +
> + dev_info(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
> + jiffies_to_msecs(2147483647), HZ);
This is debug code. Don't use dev_info().
> +
> + 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);
> +
> + LOG_INFO(priv, INIT, "HIDR supported\n");
> +
> + /* 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_VENDOR_ID_INTEL, 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;
> +}
Actually return sdio_register_driver() would do the same trick.
> +
> +static void __exit iwmct_exit(void)
> +{
> + sdio_unregister_driver(&iwmct_driver);
> +}
> +
> +module_init(iwmct_init);
> +module_exit(iwmct_exit);
> +
At some point I got lost in this code. It contains more debug statements
and infrastructure than actual code as it seems. Can you please clean
this up. I mentioned it above. Just use dynamic_printk and you should be
have something clean and simple.
Regards
Marcel
^ permalink raw reply
* Re: Ath5k data aborts
From: Krzysztof Halasa @ 2009-10-10 12:51 UTC (permalink / raw)
To: Nick Kossifidis; +Cc: linux-wireless, ath5k-devel, netdev
In-Reply-To: <40f31dec0910100356i470a93d0x3244867e1160e9df@mail.gmail.com>
Nick Kossifidis <mickflemm@gmail.com> writes:
>> +#if 0
>> AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
>> AR5K_PCICFG_SLEEP_CLOCK_EN);
>> +#endif
> Interesting, can you provide us with an eeprom info dump from your
> card (using ath_info tool from madwifi svn) ?
> It seems we need to skip sleep clock operation in your case.
Sure (MAC changed):
sleep_ctl reg 00000000 reset_ctl reg 00000000
-==Device Information==-
MAC Revision: 5213A (0x59)
Device type: 3
5GHz PHY Revision: 5112B (0x36)
/============== EEPROM Information =============\
| EEPROM Version: 4.8 | EEPROM Size: 16 kbit |
| EEMAP: 1 | Reg. Domain: 0x00 |
|================= Capabilities ================|
| 802.11a Support: yes | Turbo-A disabled: no |
| 802.11b Support: yes | Turbo-G disabled: no |
| 802.11g Support: yes | 2GHz XR disabled: no |
| RFKill Support: yes | 5GHz XR disabled: no |
| 32kHz Crystal: yes | |
\===============================================/
/=========================================================\
| Calibration data common for all modes |
|=========================================================|
| CCK/OFDM gain delta: 3 |
| CCK/OFDM power delta: 10 |
| Scaled CCK delta: 15 |
| 2GHz Antenna gain: 1 |
| 5GHz Antenna gain: 1 |
| Turbo 2W maximum dBm: 32 |
| Target power start: 0x1a5 |
| EAR Start: 0x20f |
\=========================================================/
/=========================================================\
| Calibration data for 802.11a operation |
|=========================================================|
| I power: 0x0a | Q power: 0x1e |
| Use fixed bias: 0x01 | Max turbo power: 0x20 |
| Max XR power: 0x24 | Switch Settling Time: 0x2d |
| Tx/Rx attenuation: 0x0f | TX end to XLNA On: 0x02 |
| TX end to XPA Off: 0x00 | TX end to XPA On: 0x0e |
| 62db Threshold: 0x0f | XLNA gain: 0x0d |
| XPD: 0x01 | XPD gain: 0x05 |
| I gain: 0x0a | Tx/Rx margin: 0x0b |
| False detect backoff: 0x00 | Noise Floor Threshold: -54 |
| ADC desired size: -32 | PGA desired size: -80 |
|=========================================================|
| Antenna control 0: 0x00 | Antenna control 1: 0x02 |
| Antenna control 2: 0x01 | Antenna control 3: 0x00 |
| Antenna control 4: 0x00 | Antenna control 5: 0x00 |
| Antenna control 6: 0x01 | Antenna control 7: 0x02 |
| Antenna control 8: 0x00 | Antenna control 9: 0x00 |
| Antenna control 10: 0x00 | Antenna control 11: 0x00 |
|=========================================================|
| Octave Band 0: 2 | db 0: 2 |
| Octave Band 1: 2 | db 1: 2 |
| Octave Band 2: 2 | db 2: 2 |
| Octave Band 3: 2 | db 3: 2 |
\=========================================================/
/============== Per rate power calibration ===========\
| Freq | 6-24Mbit/s | 36Mbit/s | 48Mbit/s | 54Mbit/s |
|======|============|==========|===========|==========|
| 4920 | 18.00 | 16.00 | 14.00 | 12.00 |
|======|============|==========|===========|==========|
| 5040 | 18.00 | 16.00 | 14.00 | 12.00 |
|======|============|==========|===========|==========|
| 5170 | 18.00 | 16.00 | 15.00 | 13.00 |
|======|============|==========|===========|==========|
| 5240 | 19.00 | 17.00 | 15.00 | 13.00 |
|======|============|==========|===========|==========|
| 5320 | 19.00 | 17.00 | 15.00 | 13.00 |
|======|============|==========|===========|==========|
| 5500 | 19.00 | 16.00 | 14.00 | 13.00 |
|======|============|==========|===========|==========|
| 5700 | 18.00 | 16.00 | 14.00 | 13.00 |
|======|============|==========|===========|==========|
| 5825 | 17.00 | 15.00 | 13.00 | 12.00 |
|======|============|==========|===========|==========|
| 5360 | 19.01 | 19.01 | 19.01 | 19.01 |
|======|============|==========|===========|==========|
| 5720 | 19.00 | 19.00 | 19.00 | 19.00 |
\=====================================================/
/=================== Per channel power calibration ====================\
| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|
| | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 4920 | 6.75 | 16.25 | 21.00 | 22.00 | 6.00 | 6.00 | 11.25 | 22.00 |
| | [25] | [50] | [62] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 4980 | 6.25 | 15.75 | 21.25 | 21.75 | 4.75 | 4.50 | 11.25 | 21.75 |
| | [25] | [50] | [62] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5040 | 6.75 | 14.75 | 19.00 | 23.00 | 3.25 | 3.25 | 11.25 | 23.00 |
| | [25] | [47] | [57] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5170 | 7.25 | 15.25 | 18.50 | 23.00 | 2.25 | 2.75 | 12.00 | 23.00 |
| | [25] | [46] | [55] | [61] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5240 | 8.00 | 16.75 | 20.50 | 23.00 | 1.75 | 3.00 | 12.25 | 23.00 |
| | [25] | [48] | [58] | [61] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5320 | 8.75 | 17.50 | 21.25 | 23.00 | 2.00 | 3.50 | 13.00 | 23.00 |
| | [25] | [48] | [58] | [59] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5500 | 9.75 | 17.75 | 21.50 | 23.00 | 2.25 | 4.50 | 14.50 | 23.00 |
| | [25] | [46] | [56] | [57] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5650 | 10.25 | 18.00 | 21.00 | 23.00 | 1.75 | 5.00 | 15.00 | 23.00 |
| | [25] | [45] | [54] | [56] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5745 | 10.75 | 19.75 | 23.00 | 23.00 | 1.25 | 5.00 | 15.00 | 23.00 |
| | [25] | [50] | [57] | [57] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 5825 | 10.25 | 20.00 | 22.25 | 22.25 | 0.50 | 4.75 | 14.75 | 22.25 |
| | [25] | [50] | [62] | [63] | [20] | [35] | [63] | |
\======================================================================/
/=========================================================\
| Calibration data for 802.11b operation |
|=========================================================|
| I power: 0x00 | Q power: 0x00 |
| Use fixed bias: 0x00 | Max turbo power: 0x00 |
| Max XR power: 0x00 | Switch Settling Time: 0x28 |
| Tx/Rx attenuation: 0x1e | TX end to XLNA On: 0x02 |
| TX end to XPA Off: 0x00 | TX end to XPA On: 0x07 |
| 62db Threshold: 0x1c | XLNA gain: 0x0d |
| XPD: 0x01 | XPD gain: 0x05 |
| I gain: 0x0a | Tx/Rx margin: 0x21 |
| False detect backoff: 0x00 | Noise Floor Threshold: -1 |
| ADC desired size: -38 | PGA desired size: -80 |
|=========================================================|
| Antenna control 0: 0x00 | Antenna control 1: 0x02 |
| Antenna control 2: 0x11 | Antenna control 3: 0x01 |
| Antenna control 4: 0x01 | Antenna control 5: 0x01 |
| Antenna control 6: 0x01 | Antenna control 7: 0x12 |
| Antenna control 8: 0x02 | Antenna control 9: 0x02 |
| Antenna control 10: 0x02 | Antenna control 11: 0x00 |
|=========================================================|
| Octave Band 0: 2 | db 0: 2 |
| Octave Band 1: 2 | db 1: 2 |
| Octave Band 2: 0 | db 2: 0 |
| Octave Band 3: 0 | db 3: 0 |
\=========================================================/
/============== Per rate power calibration ===========\
| Freq | 1Mbit/s | 2Mbit/s | 5.5Mbit/s | 11Mbit/s |
|======|============|==========|===========|==========|
| 2412 | 19.01 | 19.01 | 19.01 | 19.01 |
|======|============|==========|===========|==========|
| 2484 | 19.00 | 19.00 | 19.00 | 19.00 |
\=====================================================/
/=================== Per channel power calibration ====================\
| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|
| | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2412 | 8.00 | 15.25 | 19.50 | 23.25 | 1.50 | 3.75 | 12.00 | 23.25 |
| | [25] | [46] | [56] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2437 | 7.75 | 16.00 | 21.00 | 22.50 | 1.25 | 3.50 | 11.75 | 22.50 |
| | [25] | [49] | [60] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2472 | 7.25 | 15.75 | 21.00 | 21.75 | 0.75 | 3.25 | 11.25 | 21.75 |
| | [25] | [50] | [61] | [63] | [20] | [35] | [63] | |
\======================================================================/
/=========================================================\
| Calibration data for 802.11g operation |
|=========================================================|
| I power: 0x00 | Q power: 0x17 |
| Use fixed bias: 0x01 | Max turbo power: 0x20 |
| Max XR power: 0x26 | Switch Settling Time: 0x28 |
| Tx/Rx attenuation: 0x23 | TX end to XLNA On: 0x02 |
| TX end to XPA Off: 0x00 | TX end to XPA On: 0x0e |
| 62db Threshold: 0x1c | XLNA gain: 0x0d |
| XPD: 0x01 | XPD gain: 0x05 |
| I gain: 0x0a | Tx/Rx margin: 0x21 |
| False detect backoff: 0x00 | Noise Floor Threshold: -1 |
| ADC desired size: -32 | PGA desired size: -80 |
|=========================================================|
| Antenna control 0: 0x00 | Antenna control 1: 0x02 |
| Antenna control 2: 0x11 | Antenna control 3: 0x01 |
| Antenna control 4: 0x01 | Antenna control 5: 0x01 |
| Antenna control 6: 0x01 | Antenna control 7: 0x12 |
| Antenna control 8: 0x02 | Antenna control 9: 0x02 |
| Antenna control 10: 0x02 | Antenna control 11: 0x02 |
|=========================================================|
| Octave Band 0: 2 | db 0: 2 |
| Octave Band 1: 2 | db 1: 2 |
| Octave Band 2: 0 | db 2: 0 |
| Octave Band 3: 0 | db 3: 0 |
\=========================================================/
/============== Per rate power calibration ===========\
| Freq | 6-24Mbit/s | 36Mbit/s | 48Mbit/s | 54Mbit/s |
|======|============|==========|===========|==========|
| 2412 | 19.00 | 17.01 | 16.00 | 15.01 |
|======|============|==========|===========|==========|
| 2437 | 19.00 | 18.00 | 17.00 | 16.00 |
|======|============|==========|===========|==========|
| 2472 | 19.00 | 17.01 | 16.01 | 15.00 |
\=====================================================/
/=================== Per channel power calibration ====================\
| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|
| | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2412 | 7.25 | 16.00 | 21.75 | 22.50 | 0.25 | 3.75 | 11.50 | 22.50 |
| | [25] | [50] | [62] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2437 | 7.00 | 16.25 | 20.75 | 21.75 | 0.00 | 3.50 | 11.25 | 21.75 |
| | [25] | [50] | [61] | [63] | [20] | [35] | [63] | |
|======|=======|=======|=======|=======|=======|=======|=======|=======|
| 2472 | 6.50 | 15.50 | 20.75 | 21.00 | 0.00 | 3.00 | 10.50 | 21.00 |
| | [25] | [50] | [62] | [63] | [20] | [35] | [63] | |
\======================================================================/
GPIO registers: CR 0x00000000, DO 0x00000000, DI 0x00000001
EEPROM dump (2048 bytes)
==============================================
0000: 0013 168c 0200 0001 0000 5001 0000 1012
0008: 185f 1c0a 0100 0000 01c2 0002 c606 0001
0010: 0000 0000 0000 0000 0000 0000 0000 0000
0018: 0000 0000 0000 0000 0000 3445 1223 0001
0020: 0000 0000 0000 0000 0000 0000 0000 0000
0028: 0000 0000 0000 0000 0000 0000 0000 0000
0030: 0000 0000 0000 0000 0000 0000 0000 0000
0038: 0000 0000 0000 0000 0000 5aa5 0000 0000
0040: 0313 4943 2053 7104 1202 0400 0306 0001
0048: 0000 0500 410e 39b1 1eb5 4e2d 3056 ffff
0050: e902 0700 0106 0000 0100 1500 0752 4101
0058: 6874 7265 736f 4320 6d6f 756d 696e 6163
0060: 6974 6e6f 2c73 4920 636e 002e 5241 3035
0068: 3130 302d 3030 2d30 3030 3030 5700 7269
0070: 6c65 7365 2073 414c 204e 6552 6566 6572
0078: 636e 2065 6143 6472 3000 0030 00ff 2100
0080: 0602 2201 0205 8d80 005b 0522 4002 8954
0088: 2200 0205 1b00 00b7 0522 8002 12a8 2201
0090: 0205 3600 016e 0522 0002 2551 2202 0205
0098: 6c00 02dc 0522 8002 37f9 2203 0205 a200
00a0: 044a 0222 0803 0822 0604 0100 2312 4534
00a8: 0222 0105 00ff 0000 0000 0000 0000 0000
00b0: ffff ffff ffff ffff ffff ffff ffff ffff
00b8: ffff ffff ffff ffff ffff ffff 0000 0000
00c0: ee2b 4008 5a07 0101 420f 41a5 0101 3002
00c8: 0003 0000 0000 0000 0000 0000 0000 0000
00d0: 0000 0000 0000 0000 2d3c 0081 0000 0108
00d8: 0000 e049 2492 020f 000e b0ca 21ab 4024
00e0: 0af1 000b 0000 0000 0000 0000 0000 0000
00e8: 0000 0000 0000 0000 0000 0000 0000 0000
00f0: 0000 0000 2878 0091 0410 4148 2082 da22
00f8: 021c 0007 b0ff 01ab 4012 0001 8970 21ac
0100: 0000 0000 0000 0000 0000 0000 0000 0000
0108: 0000 0000 0000 0000 0000 288c 0091 0410
0110: 4148 2082 e022 021c 000e b0ff 21ab 4012
0118: 7851 8970 1320 21ac 00bb 0003 0000 0000
0120: 0000 0000 0000 0000 0000 0000 0000 0000
0128: 1013 1112 1440 3031 3234 0000 0000 0000
0130: 0000 0000 0000 0000 0000 0000 0000 0000
0138: 0000 0000 0000 0000 0000 0000 0000 0000
0140: 0000 0000 0000 0000 0000 0000 0000 0000
0148: 0000 0000 0000 0000 0000 0000 0000 0000
0150: 2418 4a30 6858 aa8c cdbd 411b 5854 0599
0158: 1818 192d 3f19 5755 0599 1213 192d 3b1b
0160: 5c4c 1956 0d0d 192d 3d1d 5c4a 1935 0b09
0168: 1930 4320 5c52 0d57 0c07 1931 4623 5c55
0170: 0557 0e08 1934 4727 5c56 0555 1209 193a
0178: 4829 5c54 0934 1407 193c 4f2b 5c5c 00f9
0180: 1405 193c 5029 5959 0599 1302 193b 3d20
0188: 5d4e 1d55 0f06 1930 401f 5a54 0d78 0e05
0190: 192f 3f1d 5754 0979 0d03 192d 401d 5a57
0198: 0599 0f01 192e 411c 5753 0979 0e00 192d
01a0: 3e1a 5453 0599 0c00 192a 1892 0718 3092
01a8: 0718 4a92 079a 589a 279a 689a 279a 8c9a
01b0: 071a b492 071a cd89 e698 709e 79e7 b89a
01b8: 69a6 709a 381f 899a 48a0 ac9a 385e 4c58
01c0: 5c68 bdc1 cd00 2222 2423 2464 2400 5052
01c8: 5a60 62c0 c1c9 2262 2224 2423 6323 7075
01d0: a200 0000 0000 2868 2800 0000 0000 7075
01d8: 9da2 0000 0000 2166 6621 0000 0000 8989
01e0: 0000 0000 0000 2626 0000 0000 0000 4a56
01e8: 0000 0000 0000 3c3c 0000 0000 0000 4c68
01f0: 8cb4 bdc1 cd00 2424 2424 3c7c 3c00 7075
01f8: ac00 0000 0000 2060 2000 0000 0000 7075
0200: ac00 0000 0000 1d5d 1d00 0000 0000 8989
0208: 0000 0000 0000 1e1e 0000 0000 0000 ea0e
0210: c000 0e07 8042 a204 0002 0e03 8186 9858
0218: 0000 0e01 800c 9824 0707 0e02 8063 9860
0220: 0003 03ff a210 0080 6333 03ff a214 0010
0228: 6c10 03ff a21c 1883 800a 03ff a220 0188
0230: 30c6 05ff c0fd 1001 c8f5 707f c8fc 1000
0238: c85a 2001 c85c 2002 c85e 2001 c8fe 1001
0240: c519 1001 cc01 2001 cc03 2001 cc8b 1001
0248: cc8c 1001 dc92 1001 0fff 8081 1230 0001
0250: 0fff 8010 982c a002 09ff 8063 0000 0000
0258: 0000 0000 0000 0000 0000 0000 0000 0000
0260: 0000 0000 0000 0000 0000 0000 0000 0000
0268: 0000 0000 0000 0000 0000 0000 0000 0000
0270: 0000 0000 0000 0000 0000 0000 0000 0000
0278: 0000 0000 0000 0000 0000 0000 0000 0000
0280: 0000 0000 0000 0000 0000 0000 0000 0000
0288: 0000 0000 0000 0000 0000 0000 0000 0000
0290: 0000 0000 0000 0000 0000 0000 0000 0000
0298: 0000 0000 0000 0000 0000 0000 0000 0000
02a0: 0000 0000 0000 0000 0000 0000 0000 0000
02a8: 0000 0000 0000 0000 0000 0000 0000 0000
02b0: 0000 0000 0000 0000 0000 0000 0000 0000
02b8: 0000 0000 0000 0000 0000 0000 0000 0000
02c0: 0000 0000 0000 0000 0000 0000 0000 0000
02c8: 0000 0000 0000 0000 0000 0000 0000 0000
02d0: 0000 0000 0000 0000 0000 0000 0000 0000
02d8: 0000 0000 0000 0000 0000 0000 0000 0000
02e0: 0000 0000 0000 0000 0000 0000 0000 0000
02e8: 0000 0000 0000 0000 0000 0000 0000 0000
02f0: 0000 0000 0000 0000 0000 0000 0000 0000
02f8: 0000 0000 0000 0000 0000 0000 0000 0000
0300: 0000 0000 0000 0000 0000 0000 0000 0000
0308: 0000 0000 0000 0000 0000 0000 0000 0000
0310: 0000 0000 0000 0000 0000 0000 0000 0000
0318: 0000 0000 0000 0000 0000 0000 0000 0000
0320: 0000 0000 0000 0000 0000 0000 0000 0000
0328: 0000 0000 0000 0000 0000 0000 0000 0000
0330: 0000 0000 0000 0000 0000 0000 0000 0000
0338: 0000 0000 0000 0000 0000 0000 0000 0000
0340: 0000 0000 0000 0000 0000 0000 0000 0000
0348: 0000 0000 0000 0000 0000 0000 0000 0000
0350: 0000 0000 0000 0000 0000 0000 0000 0000
0358: 0000 0000 0000 0000 0000 0000 0000 0000
0360: 0000 0000 0000 0000 0000 0000 0000 0000
0368: 0000 0000 0000 0000 0000 0000 0000 0000
0370: 0000 0000 0000 0000 0000 0000 0000 0000
0378: 0000 0000 0000 0000 0000 0000 0000 0000
0380: 0000 0000 0000 0000 0000 0000 0000 0000
0388: 0000 0000 0000 0000 0000 0000 0000 0000
0390: 0000 0000 0000 0000 0000 0000 0000 0000
0398: 0000 0000 0000 0000 0000 0000 0000 0000
03a0: 0000 0000 0000 0000 0000 0000 0000 0000
03a8: 0000 0000 0000 0000 0000 0000 0000 0000
03b0: 0000 0000 0000 0000 0000 0000 0000 0000
03b8: 0000 0000 0000 0000 0000 0000 0000 0000
03c0: 0000 0000 0000 0000 0000 0000 0000 0000
03c8: 0000 0000 0000 0000 0000 0000 0000 0000
03d0: 0000 0000 0000 0000 0000 0000 0000 0000
03d8: 0000 0000 0000 0000 0000 0000 0000 0000
03e0: 0000 0000 0000 0000 0000 0000 0000 0000
03e8: 0000 0000 0000 0000 0000 0000 0000 0000
03f0: 0000 0000 0000 0000 0000 0000 0000 0000
03f8: 0000 0000 0000 0000 0000 0000 0000 0000
==============================================
STA_ID0: 00:00:00:00:00:00
STA_ID1: 0x10000000, AP: 0, IBSS: 0, KeyCache Disable: 0
TIMER0: 0x0000fdee, TBTT: 65006, TU: 0xc749fdee
TIMER1: 0x0007ffff, DMAb: 65535, TU: 0xc749ffff (+529)
TIMER2: 0x015bcffd, SWBA: 31231, TU: 0xc76b79ff (+2194449)
TIMER3: 0x0000fddf, ATIM: 64991, TU: 0xc749fddf (-15)
TSF: 0xcad0ef1d26f6ab81, TSFTU: 48554, TU: 0xc749bdaa
BEACON: 0x007bfbe7
LAST_TSTP: 0xfbe5fbef
--
Krzysztof Halasa
^ permalink raw reply
* Re: 2.6.31.[12] ath5k regression
From: Bob Copeland @ 2009-10-10 12:58 UTC (permalink / raw)
To: Richard Zidlicky; +Cc: linux-wireless
In-Reply-To: <20091009143922.GA7848@linux-m68k.org>
On Fri, Oct 09, 2009 at 04:39:22PM +0200, Richard Zidlicky wrote:
> - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
> + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
> if (ret) {
> ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
> goto err;
So, this change effectively just ensures we now program the pcu registers
at startup (every other time chan should not be null). So my guess is
programming the pcu actually causes some problem. Can you try this patch
instead?
Also, since you're using adhoc there may be a path that's somewhat
different from infrastructure mode, please check dmesg after applying the
patch and be sure that you only see "ath5k: reset with change_channel=true"
once per driver load.
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 8fa4393..c099fa2 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -1376,9 +1376,8 @@ static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
for (i = 0; i < size; i++) {
/* On channel change there is
* no need to mess with PCU */
- if (change_channel &&
- ini_regs[i].ini_register >= AR5K_PCU_MIN &&
- ini_regs[i].ini_register <= AR5K_PCU_MAX)
+ if (ini_regs[i].ini_register >= AR5K_PCU_MIN &&
+ ini_regs[i].ini_register <= AR5K_PCU_MAX)
continue;
switch (ini_regs[i].ini_mode) {
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 3dab3d8..4b8ccbe 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -880,6 +880,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ATH5K_TRACE(ah->ah_sc);
+ if (!change_channel)
+ printk(KERN_DEBUG "ath5k: reset with change_channel=true\n");
+
s_ant = 0;
ee_mode = 0;
staid1_flags = 0;
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply related
* Re: Ath5k data aborts
From: Krzysztof Halasa @ 2009-10-10 13:05 UTC (permalink / raw)
To: Nick Kossifidis; +Cc: linux-wireless, ath5k-devel, netdev
In-Reply-To: <40f31dec0910100356i470a93d0x3244867e1160e9df@mail.gmail.com>
Nick Kossifidis <mickflemm@gmail.com> writes:
> Interesting, can you provide us with an eeprom info dump from your
> card (using ath_info tool from madwifi svn) ?
> It seems we need to skip sleep clock operation in your case.
BTW the problem doesn't always happen immediately, sometimes it shows up
only on second or further hostapd invocation. I think in only occurs
while hostapd is starting - if it starts successfully, it works.
--
Krzysztof Halasa
^ permalink raw reply
* Re: 2.6.31.[12] ath5k regression
From: Bob Copeland @ 2009-10-10 13:31 UTC (permalink / raw)
To: Richard Zidlicky; +Cc: linux-wireless
In-Reply-To: <20091010125824.GA18841@hash.localnet>
On Sat, Oct 10, 2009 at 8:58 AM, Bob Copeland <me@bobcopeland.com> wrote:
> ATH5K_TRACE(ah->ah_sc);
>
> + if (!change_channel)
> + printk(KERN_DEBUG "ath5k: reset with change_channel=true\n");
> +
Of course I meant change_channel=false in the format string but what's
important is how often it is printed :)
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* Re: deauthentication and disassociation nl80211 commands
From: John Klehm @ 2009-10-10 16:04 UTC (permalink / raw)
To: Maxim Levitsky; +Cc: hostap@lists.shmoo.com, linux-wireless
In-Reply-To: <1255146340.3542.10.camel@maxim-laptop>
On Fri, Oct 9, 2009 at 10:45 PM, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
>
> Nobody uses driver_nl80211 but me?
>
I do and I'm sure there are more people like me that get great use out
of the older working version.
Of course Id love to have an updated version but I understand that if
I don't have the time to write it then it makes it hard to complain :P
I (and others I'm sure) appreciate your efforts to document what needs
to be fixed Maxim. No doubt useful to the person that finally takes a
crack at the nl80211 code.
Cheers,
--John Klehm
^ permalink raw reply
* Re: deauthentication and disassociation nl80211 commands
From: Johannes Berg @ 2009-10-10 16:24 UTC (permalink / raw)
To: Maxim Levitsky; +Cc: hostap@lists.shmoo.com, linux-wireless
In-Reply-To: <1254708707.24430.68.camel@maxim-laptop>
[-- Attachment #1: Type: text/plain, Size: 1174 bytes --]
On Mon, 2009-10-05 at 04:11 +0200, Maxim Levitsky wrote:
> My hacky patch that was rejected on the grounds that it is not right to
> introduce the driver dependent behavior might actually be the correct
> solution. It just makes the wpa_supplicant_disassociate do both
> disassociation and deauthentication, as was always assumed by the
> wpa_supplicant core.
Jouni just wanted to have what he felt was a workaround in
driver_nl80211.c rather than the core code.
> Or kernel should became smarter and do the work for wpa_supplicant.
I still disagree. Why should the kernel deauthenticate when userspace
disassociated.
On the other hand, I think Jouni's argument is that you should be able
to authenticate (force an auth frame exchange) even while authenticated.
I don't really disagree with that all that much, but I'm not sure how to
cleanly fit it in. mac80211 would have to reset the auth state without
sending a deauth.
johannes
(NB: I'm off to Japan on Monday. Sorry I've been slow with email, but
had lots of stuff to do and then planning the next trip, I hope it'll
improve once I return on the 22nd -- well after the weekend then)
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Tomas Winkler @ 2009-10-10 18:05 UTC (permalink / raw)
To: Marcel Holtmann
Cc: davem, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <1255172508.19127.22.camel@localhost.localdomain>
On Sat, Oct 10, 2009 at 1:01 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Tomas,
>
>> 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>
>> ---
>> drivers/misc/Kconfig | 1 +
>> drivers/misc/Makefile | 1 +
>> drivers/misc/iwmc3200top/Kconfig | 20 +
>> drivers/misc/iwmc3200top/Makefile | 29 ++
>> drivers/misc/iwmc3200top/debugfs.c | 145 +++++++
>> drivers/misc/iwmc3200top/debugfs.h | 61 +++
>> drivers/misc/iwmc3200top/fw-download.c | 359 ++++++++++++++++
>> drivers/misc/iwmc3200top/fw-msg.h | 113 +++++
>> drivers/misc/iwmc3200top/iwmc3200top.h | 202 +++++++++
>> drivers/misc/iwmc3200top/log.c | 339 +++++++++++++++
>> drivers/misc/iwmc3200top/log.h | 158 +++++++
>> drivers/misc/iwmc3200top/main.c | 702 ++++++++++++++++++++++++++++++++
>> 12 files changed, 2130 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 68ab39d..6f85b43 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -236,5 +236,6 @@ config ISL29003
>> 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 36f733c..97f5303 100644
>> --- a/drivers/misc/Makefile
>> +++ b/drivers/misc/Makefile
>> @@ -20,5 +20,6 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
>> obj-$(CONFIG_HP_ILO) += hpilo.o
>> obj-$(CONFIG_ISL29003) += isl29003.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..a531f6c
>> --- /dev/null
>> +++ b/drivers/misc/iwmc3200top/debugfs.c
>> @@ -0,0 +1,145 @@
>> +/*
>> + * 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 "iwmc3200top.h"
>> +#include "log.h"
>> +#include "fw-msg.h"
>> +#include "debugfs.h"
>> +
>> +/* Constants definition */
>> +#define HEXADECIMAL_RADIX 16
>> +
>> +/* Functions definition */
>> +
>> +
>> +/* Debugfs macros */
>> +#define DEBUGFS_ADD_DIR(name, parent) do { \
>> + dbgfs->dir_##name = debugfs_create_dir(#name, parent); \
>> + if (!(dbgfs->dir_##name)) \
>> + goto err; \
>> +} while (0)
>> +
>> +#define DEBUGFS_ADD_FILE(name, parent) do { \
>> + dbgfs->dbgfs_##parent##_files.file_##name = \
>> + debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
>> + &iwmct_dbgfs_##name##_ops); \
>> + if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
>> + goto err; \
>> +} while (0)
>> +
>> +#define DEBUGFS_REMOVE(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 */
>> +
>> +/* Debugfs registration functions */
>> +
>> +/*
>> + * Create the debugfs files and directories
>> + *
>> + */
>
> so for me the whole debug infrastructure is way too much overhead for
> what this driver has to achieve. What is the benefit of having all these
> debugfs support. What is it trying to achieve?
There is some testing infrastracture built erround debugfs, it
exericeses the firmware. There is no use for
it outside our development so we ripped it off but removing also
debugfs will nightmare to maintain.
>
> Also all these macros really obfuscate the code for no real benefit. If
> you wanna keep debugfs support, then just use the functions directly.
> They are not that complicated that an extra abstraction layer is needed.
>
I believe the macros were borrowed from wireless code. They shalll
reduce codelines
but I have no strong feelings about them
Thanks for your comments I will address them in consequitve patch.
Thanks
Tomas
>> +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));
>> + goto err;
>> + }
>> +
>> + 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");
>> + goto err;
>> + }
>> +
>> +
>> +err:
>> + return;
>> +}
>
> goto err. Seriously. Just call return in the error case. And also there
> is a memory leak if the debugfs_create_dir fails.
>
>> +/**
>> + * Remove the debugfs files and directories
>> + *
>> + */
>> +void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
>> +{
>> + if (!dbgfs)
>> + return;
>> +
>> +
>> + DEBUGFS_REMOVE(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..24b1369
>> --- /dev/null
>> +++ b/drivers/misc/iwmc3200top/debugfs.h
>> @@ -0,0 +1,61 @@
>> +/*
>> + * 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
>> +
>> +#include <linux/debugfs.h>
>> +
>> +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 is empty if CONFIG_IWMC3200TOP_DEBUGFS is not defined */
>> +struct iwmct_debugfs {
>> +};
>
> If struct iwmct_debugfs is never referenced directly then a simple
> forward struct imwct_debugfs; declaration is good enough.
>
>> +
>> +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);
>
> This logging is overkill. Can we just hide this via pr_debug and then
> use just simply dynamic_printk support.
>
>> +
>> + 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));
>
> The access to file and parser->file. One with unaligned access and the
> other with, looks wrong. And it looks way to complicated.
>
> Can we just not have a proper __le32 type of parser->file to begin with.
>
>> +
>> + 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;
>
> This if statement is unreadable. This indentation gives me a headache.
>
> Also this function better return bool and not int.
>
>> + } 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..59e4b7a
>> --- /dev/null
>> +++ b/drivers/misc/iwmc3200top/iwmc3200top.h
>> @@ -0,0 +1,202 @@
>> +/*
>> + * 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__
>> +
>> +#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_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..96b5e4a
>> --- /dev/null
>> +++ b/drivers/misc/iwmc3200top/log.c
>> @@ -0,0 +1,339 @@
>> +/*
>> + * 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 = d->driver_data;
>> + char *str_buf;
>> + int buf_size;
>> + ssize_t ret = -EAGAIN;
>> +
>> + 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);
>> + goto exit;
>> + }
>> +
>> + if (log_get_filter_str(str_buf, buf_size) < 0)
>> + 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 = d->driver_data;
>> + char *token, *str_buf = NULL;
>> + long val;
>> + u8 src, mask;
>> +
>> + if (!count)
>> + goto err;
>> +
>> + str_buf = kzalloc(count, GFP_KERNEL);
>> + if (!str_buf) {
>> + LOG_ERROR(priv, DEBUGFS,
>> + "failed to allocate %zd bytes\n", count);
>> + goto err;
>> + }
>> +
>> + 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);
>> + goto err;
>> + }
>> +
>> + mask = val & 0xFF;
>> + src = (val & 0XFF00) >> 8;
>> + iwmct_log_set_filter(src, mask);
>> + }
>> +
>> + kfree(str_buf);
>> + return count;
>> +
>> +err:
>> + kfree(str_buf);
>> + return -EAGAIN;
>> +}
>> +
>> +ssize_t show_iwmct_log_level_fw(struct device *d,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct iwmct_priv *priv = d->driver_data;
>> + char *str_buf;
>> + int buf_size;
>> + ssize_t ret = -EAGAIN;
>> +
>> + 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);
>> + goto exit;
>> + }
>> +
>> + if (log_get_fw_filter_str(str_buf, buf_size) < 0)
>> + 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 = d->driver_data;
>> + char *token, *str_buf = NULL;
>> + long val;
>> + u8 src, mask;
>> + struct top_msg cmd;
>> + u16 cmdlen = 0;
>> + int i, rc;
>> +
>> + if (!count)
>> + goto err;
>> +
>> + str_buf = kzalloc(count, GFP_KERNEL);
>> + if (!str_buf) {
>> + LOG_ERROR(priv, DEBUGFS,
>> + "failed to allocate %zd bytes\n", count);
>> + goto err;
>> + }
>> +
>> + 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);
>> + goto err;
>> + }
>> +
>> + 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));
>> +
>> + rc = iwmct_send_hcmd(priv, (u8 *) &cmd, cmdlen);
>> + if (rc) {
>> + LOG_ERROR(priv, DEBUGFS,
>> + "Failed to send %d bytes of fwcmd, rc=%d\n",
>> + cmdlen, rc);
>> + goto err;
>> + } else
>> + LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
>> +
>> + kfree(str_buf);
>> + return count;
>> +
>> +err:
>> + kfree(str_buf);
>> + return -EAGAIN;
>> +}
>> +
>> 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__ */
>
> Seriously. Please just use dynamic_printk and lets remove all this log
> infrastructure. It is way too much overhead for too little benefit.
>
>> diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
>> new file mode 100644
>> index 0000000..09f8d06
>> --- /dev/null
>> +++ b/drivers/misc/iwmc3200top/main.c
>> @@ -0,0 +1,702 @@
>> +/*
>> + * 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/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 ""
>> +#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);
>> +
>> +
>> +#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, val, i;
>> + int iosize;
>> + u32 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]);
>> + if (barker != IWMC_BARKER_ACK &&
>> + (barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
>> + /* Handle Top Commhub message.
>> + * Current handling - treat all message as
>> + * logger messages and print the context as a string. */
>> + sdio_release_host(priv->func);
>> + handle_top_message(priv, (u8 *)buf, iosize);
>> + goto exit;
>> + }
>> +
>> + /* verify basic barker sanity */
>> + for (i = 1; i < 4; i++)
>> + if (buf[i] != buf[0]) {
>> + LOG_ERROR(priv, IRQ, "Corrupted barker,"
>> + "buf[%d]=%x buf[0]=%x\n",
>> + i, buf[i], buf[0]);
>> + goto exit_release;
>> + }
>> +
>> + val = atomic_read(&priv->dev_sync);
>> +
>> + switch (val) {
>> + case 0:
>> + /* we expect to recieve REBOOT BARKER */
>> + if ((barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
>> + LOG_ERROR(priv, IRQ, "Expecting for reboot barker %x,"
>> + "but got %x\n",
>> + IWMC_BARKER_REBOOT,
>> + (barker & BARKER_DNLOAD_BARKER_MSK));
>> + goto exit_release;
>> + }
>> +
>> + 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_inc(&priv->dev_sync);
>> + goto exit_release;
>> + }
>> + break;
>> +
>> + case 1:
>> + /* we expect to recieve ACK BARKER */
>> + if (barker != IWMC_BARKER_ACK) {
>> + LOG_INFO(priv, IRQ, "Expecting for ACK barker[%x],"
>> + "got this instead %x\n",
>> + IWMC_BARKER_ACK, barker);
>> + goto exit_release;
>> + }
>> + kfree(buf);
>> + atomic_set(&priv->dev_sync, 0);
>> + atomic_set(&priv->reset, 0);
>> + break;
>> +
>> + default:
>> + LOG_INFO(priv, IRQ, "Wrong dev_sync %d\n", val);
>> + break;
>> + }
>> +
>> + 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");
>> +
>> + return;
>> +
>> +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);
>
> Most of them are missing descriptions. And do we really need them? What
> cases are they trying to work around?
>
>> +
>> +#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)
>> +{
>> + return sprintf(buf, "%s\n",
>> + ((struct iwmct_priv *)d->driver_data)->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
>
> First module parameters and now device attributes. Why?
>
>> +
>> +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_info(&func->dev, "enter iwmct_probe\n");
>> +
>> + dev_info(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
>> + jiffies_to_msecs(2147483647), HZ);
>
> This is debug code. Don't use dev_info().
>
>> +
>> + 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);
>> +
>> + LOG_INFO(priv, INIT, "HIDR supported\n");
>> +
>> + /* 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_VENDOR_ID_INTEL, 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;
>> +}
>
> Actually return sdio_register_driver() would do the same trick.
>
>> +
>> +static void __exit iwmct_exit(void)
>> +{
>> + sdio_unregister_driver(&iwmct_driver);
>> +}
>> +
>> +module_init(iwmct_init);
>> +module_exit(iwmct_exit);
>> +
>
> At some point I got lost in this code. It contains more debug statements
> and infrastructure than actual code as it seems. Can you please clean
> this up. I mentioned it above. Just use dynamic_printk and you should be
> have something clean and simple.
>
> Regards
>
> Marcel
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* ath9k ar9220-ar9223 problem
From: Thomas Budicin @ 2009-10-10 17:40 UTC (permalink / raw)
To: linux-wireless
Hi!
I'm fromItaly I have a problem with a mini pci card with two chip
onboard ar9220 and ar9223.
When i try to load ath9k kernel 2.6.31 i get
ath: EEPROM regdomain: 0x164
ath: EEPROM indicates we should expect a direct regpair map
ath: invalid regulatory domain/country code 0x164
ath: Invalid EEPROM contents
Can you help me?
Rgds,
Thomas
^ permalink raw reply
* Re: BUG? I can reproduce "Association request to the driver failed" at will
From: Johannes Berg @ 2009-10-10 18:39 UTC (permalink / raw)
To: Holger Schurig; +Cc: linux-wireless, hostap
In-Reply-To: <200909211309.40476.hs4233@mail.mn-solutions.de>
[-- Attachment #1: Type: text/plain, Size: 2636 bytes --]
Sorry to warm this up ...
> 1253527140.795498: State: COMPLETED -> AUTHENTICATING
> 1253527140.795515: EAPOL: External notification - EAP success=0
> 1253527140.795530: EAPOL: External notification - EAP fail=0
> 1253527140.795542: EAPOL: External notification - portControl=Auto
> 1253527140.795559: nl80211: Authenticate (ifindex=34)
> 1253527140.795572: * bssid=00:13:19:80:da:30
> 1253527140.795587: * freq=2412
> 1253527140.795598: * SSID - hexdump_ascii(len=5):
> 4d 4e 57 50 41 MNWPA
> 1253527140.795630: * IEs - hexdump(len=0): [NULL]
> 1253527140.795643: * Auth Type 0
> 1253527140.795683: nl80211: Authentication request send successfully
> 1253527140.795707: RTM_NEWLINK: operstate=1 ifi_flags=0x11043 ([UP][RUNNING][LOWER_UP])
> 1253527140.795725: RTM_NEWLINK, IFLA_IFNAME: Interface 'eth1' added
> 1253527140.953161: nl80211: Event message available
> 1253527140.953200: nl80211: MLME event 37
> 1253527140.953216: SME: Authentication response: peer=00:13:19:80:da:30 auth_type=0 status_code=0
> 1253527140.953243: Trying to associate with 00:13:19:80:da:30 (SSID='MNWPA' freq=2412 MHz)
> 1253527140.953257: State: AUTHENTICATING -> ASSOCIATING
> 1253527140.953270: wpa_driver_nl80211_set_operstate: operstate 1->0 (DORMANT)
> 1253527140.953284: nl80211: Operstate: linkmode=-1, operstate=5
> 1253527140.953901: nl80211: Associate (ifindex=34)
> 1253527140.953919: * bssid=00:13:19:80:da:30
> 1253527140.953934: * freq=2412
> 1253527140.953945: * SSID - hexdump_ascii(len=5):
> 4d 4e 57 50 41 MNWPA
> 1253527140.953977: * IEs - hexdump(len=24): dd 16 00 50 f2 01 01 00 00 50 f2 02 01 00 00 50 f2 02 01 00 00 50 f2 02
> 1253527140.954064: nl80211: MLME command failed: ret=-114 (Operation already in progress)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 1253527140.954086: Association request to the driver failed
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 1253527140.954113: RTM_NEWLINK: operstate=0 ifi_flags=0x11003 ([UP][LOWER_UP])
> 1253527140.954131: RTM_NEWLINK, IFLA_IFNAME: Interface 'eth1' added
>
>
> The "Association request to the driver failed" will
> be shown even without "-d". Also note that the association
> seems to actually work, e.g. I can ping throught the
> connection.
Could this be related to the problem Maxim has been seeing? I'm not sure
how else this could happen since you seem to auth but then assoc doesn't
work, but I can't see how that could possibly happen.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: BUG? I can reproduce "Association request to the driver failed" at will
From: Johannes Berg @ 2009-10-10 18:40 UTC (permalink / raw)
To: Holger Schurig; +Cc: linux-wireless, hostap
In-Reply-To: <200909211309.40476.hs4233@mail.mn-solutions.de>
[-- Attachment #1: Type: text/plain, Size: 2636 bytes --]
Sorry to warm this up ...
> 1253527140.795498: State: COMPLETED -> AUTHENTICATING
> 1253527140.795515: EAPOL: External notification - EAP success=0
> 1253527140.795530: EAPOL: External notification - EAP fail=0
> 1253527140.795542: EAPOL: External notification - portControl=Auto
> 1253527140.795559: nl80211: Authenticate (ifindex=34)
> 1253527140.795572: * bssid=00:13:19:80:da:30
> 1253527140.795587: * freq=2412
> 1253527140.795598: * SSID - hexdump_ascii(len=5):
> 4d 4e 57 50 41 MNWPA
> 1253527140.795630: * IEs - hexdump(len=0): [NULL]
> 1253527140.795643: * Auth Type 0
> 1253527140.795683: nl80211: Authentication request send successfully
> 1253527140.795707: RTM_NEWLINK: operstate=1 ifi_flags=0x11043 ([UP][RUNNING][LOWER_UP])
> 1253527140.795725: RTM_NEWLINK, IFLA_IFNAME: Interface 'eth1' added
> 1253527140.953161: nl80211: Event message available
> 1253527140.953200: nl80211: MLME event 37
> 1253527140.953216: SME: Authentication response: peer=00:13:19:80:da:30 auth_type=0 status_code=0
> 1253527140.953243: Trying to associate with 00:13:19:80:da:30 (SSID='MNWPA' freq=2412 MHz)
> 1253527140.953257: State: AUTHENTICATING -> ASSOCIATING
> 1253527140.953270: wpa_driver_nl80211_set_operstate: operstate 1->0 (DORMANT)
> 1253527140.953284: nl80211: Operstate: linkmode=-1, operstate=5
> 1253527140.953901: nl80211: Associate (ifindex=34)
> 1253527140.953919: * bssid=00:13:19:80:da:30
> 1253527140.953934: * freq=2412
> 1253527140.953945: * SSID - hexdump_ascii(len=5):
> 4d 4e 57 50 41 MNWPA
> 1253527140.953977: * IEs - hexdump(len=24): dd 16 00 50 f2 01 01 00 00 50 f2 02 01 00 00 50 f2 02 01 00 00 50 f2 02
> 1253527140.954064: nl80211: MLME command failed: ret=-114 (Operation already in progress)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 1253527140.954086: Association request to the driver failed
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 1253527140.954113: RTM_NEWLINK: operstate=0 ifi_flags=0x11003 ([UP][LOWER_UP])
> 1253527140.954131: RTM_NEWLINK, IFLA_IFNAME: Interface 'eth1' added
>
>
> The "Association request to the driver failed" will
> be shown even without "-d". Also note that the association
> seems to actually work, e.g. I can ping throught the
> connection.
Could this be related to the problem Maxim has been seeing? I'm not sure
how else this could happen since you seem to auth but then assoc doesn't
work, but I can't see how that could possibly happen.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: David Miller @ 2009-10-11 1:58 UTC (permalink / raw)
To: tomasw
Cc: linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky,
tomas.winkler
In-Reply-To: <1ba2fa240910100238s709c31d3s6cb612f502b1086f@mail.gmail.com>
From: Tomas Winkler <tomasw@gmail.com>
Date: Sat, 10 Oct 2009 11:38:50 +0200
> On Wed, Sep 23, 2009 at 1:38 AM, Tomas Winkler <tomas.winkler@intel.com> wrote:
>> 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>
>
> Dave,
> are you going to merge this one?
> iwmc3200wifi and i200m-sdio which are already merged are usless without it
If it's not in netdev patchwork, I don't plan to add it.
If it is in patchwork, then it's in my backlog and I'll get to it.
People should never really have to ask me these questions, that's one
of the main points of:
http://patchwork.ozlabs.org/project/netdev/list/
You can always see there what's "pending".
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: David Miller @ 2009-10-11 1:59 UTC (permalink / raw)
To: tomasw
Cc: marcel, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <1ba2fa240910101105y77171591j32e6759f28556566@mail.gmail.com>
PLEASE!
Don't quote all of a big huge driver patch like that. Just quote the
parts you want to comment on!
Thank you.
^ permalink raw reply
* [PATCH] mac80211: fix logic error ibss merge bssid check
From: Felix Fietkau @ 2009-10-11 3:21 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, John W. Linville
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -544,7 +544,7 @@ static void ieee80211_sta_find_ibss(stru
"%pM\n", bss->cbss.bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
+ if (bss && !memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
sdata->dev->name, bss->cbss.bssid);
^ permalink raw reply
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Eric Dumazet @ 2009-10-11 7:40 UTC (permalink / raw)
To: David Miller
Cc: tomasw, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky,
tomas.winkler, Joe Perches
In-Reply-To: <20091010.185852.133969433.davem@davemloft.net>
David Miller a écrit :
>
> If it's not in netdev patchwork, I don't plan to add it.
>
> If it is in patchwork, then it's in my backlog and I'll get to it.
>
> People should never really have to ask me these questions, that's one
> of the main points of:
>
> http://patchwork.ozlabs.org/project/netdev/list/
>
> You can always see there what's "pending".
Me wondering if this information could be put in MAINTAINERS or Documentation/ something...
I know it only because I caught one of your answer a while ago :)
Either a per project info, or a global ref to http://patchwork.ozlabs.org/
diff --git a/MAINTAINERS b/MAINTAINERS
index e1da925..18244ad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3654,6 +3654,7 @@ NETWORKING [GENERAL]
M: "David S. Miller" <davem@davemloft.net>
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net
+W: http://patchwork.ozlabs.org/project/netdev/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
S: Maintained
F: net/
^ permalink raw reply related
* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Tomas Winkler @ 2009-10-11 8:05 UTC (permalink / raw)
To: David Miller
Cc: linville, netdev, linux-wireless, linux-mmc, yi.zhu,
inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <20091010.185852.133969433.davem@davemloft.net>
On Sun, Oct 11, 2009 at 3:58 AM, David Miller <davem@davemloft.net> wrote:
> From: Tomas Winkler <tomasw@gmail.com>
> Date: Sat, 10 Oct 2009 11:38:50 +0200
>
>> On Wed, Sep 23, 2009 at 1:38 AM, Tomas Winkler <tomas.winkler@intel.com> wrote:
>>> 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>
>>
>> Dave,
>> are you going to merge this one?
>> iwmc3200wifi and i200m-sdio which are already merged are usless without it
>
> If it's not in netdev patchwork, I don't plan to add it.
>
> If it is in patchwork, then it's in my backlog and I'll get to it.
>
> People should never really have to ask me these questions, that's one
> of the main points of:
>
> http://patchwork.ozlabs.org/project/netdev/list/
>
> You can always see there what's "pending".
Just close my eyes and there is new game to play. :)
It's not in the patchwork, so is there any reason you are not planning
to add it. The patch intention was for net-next, it looks like
I didn't mark it as such, my fault.
My primary concern is that the driver lies under misc directory so
it's not clear it should be in netdev.
This chip has 4 coms, with drivers under wireless, wimax, serial,
bluetooth. and misc. Eech of them
handled by different mailing list and sub tree. The major problem is
the top driver as other 4 comps depends
on it so I'm looking for place to refer to. Please if you have no
intention to handle it or have more concern please let me know.
Thanks
Tomas
^ permalink raw reply
* [mmotm 2009-10-09-01-07] b43/wireless possible circular locking
From: Dave Young @ 2009-10-11 9:41 UTC (permalink / raw)
To: akpm; +Cc: bcm43xx-dev, linux-wireless, linux-kernel
Hi,
I got lockdep warnings about possible circular lock with
b43 interface startup. It looks like a real problem.
[ 71.974542] wlan0: deauthenticating from 00:19:e0:db:24:de by local choice (reason=3)
[ 72.004352] b43-phy0 debug: Removing Interface type 2
[ 72.005431]
[ 72.005435] =======================================================
[ 72.006168] [ INFO: possible circular locking dependency detected ]
[ 72.006759] 2.6.32-rc3-mm1 #4
[ 72.007047] -------------------------------------------------------
[ 72.007617] ifconfig/2175 is trying to acquire lock:
[ 72.007617] (&(&rfkill->poll_work)->work){+.+...}, at: [<c0239375>] __cancel_work_timer+0x8c/0x18e
[ 72.007617]
[ 72.007617] but task is already holding lock:
[ 72.007617] (&wl->mutex){+.+.+.}, at: [<f8fa5359>] b43_op_stop+0x28/0x6a [b43]
[ 72.007617]
[ 72.007617] which lock already depends on the new lock.
[ 72.007617]
[ 72.007617]
[ 72.007617] the existing dependency chain (in reverse order) is:
[ 72.007617]
[ 72.007617] -> #1 (&wl->mutex){+.+.+.}:
[ 72.007617] [<c024b251>] __lock_acquire+0x9e2/0xb73
[ 72.007617] [<c024b449>] lock_acquire+0x67/0x84
[ 72.007617] [<c055854d>] __mutex_lock_common+0x35/0x2ca
[ 72.007617] [<c0558880>] mutex_lock_nested+0x30/0x38
[ 72.007617] [<f8fb9bcd>] b43_rfkill_poll+0x26/0xc9 [b43]
[ 72.007617] [<f8f8330e>] ieee80211_rfkill_poll+0x1f/0x21 [mac80211]
[ 72.007617] [<f8396011>] cfg80211_rfkill_poll+0x11/0x13 [cfg80211]
[ 72.007617] [<f826b740>] rfkill_poll+0x14/0x2a [rfkill]
[ 72.007617] [<c0239927>] worker_thread+0x13b/0x1ff
[ 72.007617] [<c023be0c>] kthread+0x58/0x5d
[ 72.007617] [<c0203d07>] kernel_thread_helper+0x7/0x10
[ 72.007617]
[ 72.007617] -> #0 (&(&rfkill->poll_work)->work){+.+...}:
[ 72.007617] [<c024b15c>] __lock_acquire+0x8ed/0xb73
[ 72.007617] [<c024b449>] lock_acquire+0x67/0x84
[ 72.007617] [<c02393a2>] __cancel_work_timer+0xb9/0x18e
[ 72.007617] [<c0239482>] cancel_delayed_work_sync+0xb/0xd
[ 72.007617] [<f826b71b>] rfkill_pause_polling+0x20/0x22 [rfkill]
[ 72.007617] [<f8396328>] wiphy_rfkill_stop_polling+0x10/0x12 [cfg80211]
[ 72.007617] [<f8fa5361>] b43_op_stop+0x30/0x6a [b43]
[ 72.007617] [<f8f895af>] ieee80211_stop_device+0x20/0x53 [mac80211]
[ 72.007617] [<f8f8141d>] ieee80211_stop+0x3d3/0x452 [mac80211]
[ 72.007617] [<c04e0c47>] dev_close+0x74/0x90
[ 72.007617] [<c04e082c>] dev_change_flags+0x96/0x144
[ 72.007617] [<c05262fd>] devinet_ioctl+0x212/0x468
[ 72.007617] [<c052814d>] inet_ioctl+0x8e/0xa7
[ 72.007617] [<c04d3e16>] sock_ioctl+0x1d3/0x1f7
[ 72.007617] [<c02a6b49>] vfs_ioctl+0x22/0x67
[ 72.007617] [<c02a707d>] do_vfs_ioctl+0x45f/0x493
[ 72.007617] [<c02a70f1>] sys_ioctl+0x40/0x5a
[ 72.007617] [<c020325d>] syscall_call+0x7/0xb
[ 72.007617]
[ 72.007617] other info that might help us debug this:
[ 72.007617]
[ 72.007617] 2 locks held by ifconfig/2175:
[ 72.007617] #0: (rtnl_mutex){+.+.+.}, at: [<c04e8b90>] rtnl_lock+0xf/0x11
[ 72.007617] #1: (&wl->mutex){+.+.+.}, at: [<f8fa5359>] b43_op_stop+0x28/0x6a [b43]
[ 72.007617]
[ 72.007617] stack backtrace:
[ 72.007617] Pid: 2175, comm: ifconfig Not tainted 2.6.32-rc3-mm1 #4
[ 72.007617] Call Trace:
[ 72.007617] [<c024a863>] print_circular_bug+0x8a/0x96
[ 72.007617] [<c024b15c>] __lock_acquire+0x8ed/0xb73
[ 72.007617] [<c024b449>] lock_acquire+0x67/0x84
[ 72.007617] [<c0239375>] ? __cancel_work_timer+0x8c/0x18e
[ 72.007617] [<c02393a2>] __cancel_work_timer+0xb9/0x18e
[ 72.007617] [<c0239375>] ? __cancel_work_timer+0x8c/0x18e
[ 72.007617] [<c05587c8>] ? __mutex_lock_common+0x2b0/0x2ca
[ 72.007617] [<c0248233>] ? debug_mutex_free_waiter+0x45/0x48
[ 72.007617] [<c05587d8>] ? __mutex_lock_common+0x2c0/0x2ca
[ 72.007617] [<c0239482>] cancel_delayed_work_sync+0xb/0xd
[ 72.007617] [<f826b71b>] rfkill_pause_polling+0x20/0x22 [rfkill]
[ 72.007617] [<f8396328>] wiphy_rfkill_stop_polling+0x10/0x12 [cfg80211]
[ 72.007617] [<f8fa5361>] b43_op_stop+0x30/0x6a [b43]
[ 72.007617] [<f8f895af>] ieee80211_stop_device+0x20/0x53 [mac80211]
[ 72.007617] [<f8f8141d>] ieee80211_stop+0x3d3/0x452 [mac80211]
[ 72.007617] [<c0249d42>] ? trace_hardirqs_on+0xb/0xd
[ 72.007617] [<c022fd77>] ? _local_bh_enable_ip+0x9d/0xa6
[ 72.007617] [<c022fd88>] ? local_bh_enable_ip+0x8/0xa
[ 72.007617] [<c05592a8>] ? _spin_unlock_bh+0x25/0x28
[ 72.007617] [<c04e0c47>] dev_close+0x74/0x90
[ 72.007617] [<c04e082c>] dev_change_flags+0x96/0x144
[ 72.007617] [<c05262fd>] devinet_ioctl+0x212/0x468
[ 72.007617] [<c052814d>] inet_ioctl+0x8e/0xa7
[ 72.007617] [<c04d3e16>] sock_ioctl+0x1d3/0x1f7
[ 72.007617] [<c04d3c43>] ? sock_ioctl+0x0/0x1f7
[ 72.007617] [<c02a6b49>] vfs_ioctl+0x22/0x67
[ 72.007617] [<c02a707d>] do_vfs_ioctl+0x45f/0x493
[ 72.007617] [<c0221652>] ? need_resched+0x14/0x1e
[ 72.007617] [<c0557e29>] ? schedule+0x6ed/0x6fd
[ 72.007617] [<c055b24e>] ? do_page_fault+0x29d/0x2a5
[ 72.007617] [<c02a70f1>] sys_ioctl+0x40/0x5a
[ 72.007617] [<c020325d>] syscall_call+0x7/0xb
[ 73.122930] b43-phy0 debug: Wireless interface stopped
[ 73.131557] ifconfig used greatest stack depth: 5660 bytes left
[ 73.310494] b43-phy0: Loading firmware version 410.2160 (2007-05-26 15:32:10)
[ 73.329042] b43-phy0 debug: b2062: Using crystal tab entry 19200 kHz.
[ 77.923855] b43-phy0 debug: Chip initialized
[ 77.924695] b43-phy0 debug: PIO initialized
[ 77.925410] b43-phy0 debug: QoS enabled
[ 77.941415] b43-phy0 debug: Wireless interface started
[ 77.942164] b43-phy0 debug: Adding Interface type 2
[ 77.961969] wlan0: direct probe to AP 00:19:e0:db:24:de (try 1)
[ 78.160198] wlan0: direct probe to AP 00:19:e0:db:24:de (try 2)
[ 78.164241] wlan0: direct probe responded
[ 78.164649] wlan0: authenticate with AP 00:19:e0:db:24:de (try 1)
[ 78.167341] wlan0: authenticated
[ 78.167791] wlan0: associate with AP 00:19:e0:db:24:de (try 1)
[ 78.170935] wlan0: RX ReassocResp from 00:19:e0:db:24:de (capab=0x421 status=0 aid=4)
[ 78.171690] wlan0: associated
--
Regards
dave
^ 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