From f222313a61a5e134de80767b35c672b91e78383c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 23 Jan 2006 16:59:58 -0500 Subject: [PATCH] wireless: import bcm43xx sources Import the bcm43xx driver from the upstream sources here: ftp://ftp.berlios.de/pub/bcm43xx/snapshots/bcm43xx/bcm43xx-20060123.tar.bz2 Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/COPYING | 340 ++ drivers/net/wireless/bcm43xx/Makefile | 87 + drivers/net/wireless/bcm43xx/README | 36 + drivers/net/wireless/bcm43xx/bcm43xx.h | 961 +++++ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 503 +++ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | 117 + drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1009 ++++++ drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 176 + drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 367 ++ drivers/net/wireless/bcm43xx/bcm43xx_ilt.h | 34 + drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 261 ++ drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 47 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4597 ++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_main.h | 283 ++ drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2122 +++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_phy.h | 74 + drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 592 +++ drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 88 + drivers/net/wireless/bcm43xx/bcm43xx_power.c | 358 ++ drivers/net/wireless/bcm43xx/bcm43xx_power.h | 47 + drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 1766 +++++++++ drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 93 + drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 1099 ++++++ drivers/net/wireless/bcm43xx/bcm43xx_wx.h | 36 + 24 files changed, 15093 insertions(+) create mode 100644 drivers/net/wireless/bcm43xx/COPYING create mode 100644 drivers/net/wireless/bcm43xx/Makefile create mode 100644 drivers/net/wireless/bcm43xx/README create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_dma.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_dma.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ilt.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ilt.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_leds.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_leds.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_main.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_main.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_phy.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_phy.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_pio.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_pio.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_power.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_power.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_radio.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_radio.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_wx.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_wx.h (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/COPYING b/drivers/net/wireless/bcm43xx/COPYING new file mode 100644 index 00000000000..5b6e7c66c27 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile new file mode 100644 index 00000000000..98d4efb1d12 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -0,0 +1,87 @@ +# Makefile for bcm43xx driver + +VERSION := 0.0.1 +RELEASE_NAME := bcm43xx-$(VERSION) + +# Optional path, where the SoftMAC subsystem is located. +# You may set SOFTMAC_DIR in your bashrc, for example. +SOFTMAC_DIR ?= + +KVER := $(shell uname -r) +KDIR ?= /lib/modules/$(KVER)/build +PWD := $(shell pwd) +MODPATH := $(DESTDIR)/lib/modules/$(KVER)/kernel/drivers/net/bcm43xx + +# Comment/uncomment to enable/disable debugging +DEBUG = y + + +ifeq ($(DEBUG),y) +DEBUGFS_OBJ = bcm43xx_debugfs.o +CFLAGS += -O2 -DCONFIG_BCM43XX_DEBUG +else +DEBUGFS_OBJ = +CFLAGS += -O2 +endif + +CFLAGS += -DBCM43xx_VERSION=$(VERSION) -I/lib/modules/$(KVER)/include +ifneq ($(SOFTMAC_DIR),) +CPPFLAGS := -I$(SOFTMAC_DIR) $(CPPFLAGS) +endif + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +obj-m := bcm43xx.o +bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o $(DEBUGFS_OBJ) \ + bcm43xx_radio.o bcm43xx_phy.o \ + bcm43xx_power.o bcm43xx_wx.o \ + bcm43xx_pio.o bcm43xx_ilt.o \ + bcm43xx_leds.o + +else + +default: modules + +modules: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +install: bcm43xx.ko + install -d $(MODPATH) + install -m 644 -c bcm43xx.ko $(MODPATH) + /sbin/depmod -a + +uninstall: + rm -rf $(MODPATH) + /sbin/depmod -a + +endif + +clean: + find . \( -name '*.ko' -o -name '*.o' -o -name '.tmp_versions' -o -name '*~' -o -name '.*.cmd' \ + -o -name '*.mod.c' -o -name '*.tar.bz2' -o -name '*.rej' -o -name '*.orig' \)\ + -print | xargs rm -Rf + +depend .depend dep: + $(CC) $(CFLAGS) -M *.c > .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +DISTFILES = $(shell find . \( -not -name '.' \) -print | grep -v "\.tar\.bz2" | grep -v "\/\." ) +DISTDIR = $(RELEASE_NAME) + +release: clean + @rm -rf $(DISTDIR) + @mkdir $(DISTDIR) + @chmod 777 $(DISTDIR) + @for file in $(DISTFILES); do \ + if test -d $$file; then \ + mkdir $(DISTDIR)/$$file; \ + else \ + cp -p $$file $(DISTDIR)/$$file; \ + fi; \ + done + @tar -c $(DISTDIR) | bzip2 -9 > $(RELEASE_NAME).tar.bz2 + @rm -rf $(DISTDIR) diff --git a/drivers/net/wireless/bcm43xx/README b/drivers/net/wireless/bcm43xx/README new file mode 100644 index 00000000000..64d9022de7f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/README @@ -0,0 +1,36 @@ + + BCM43xx Linux Driver Project + ============================ + +About this software +------------------- + +The goal of this project is to develop a linux driver for Broadcom +BCM43xx chips, based on the specification at +http://bcm-specs.sipsolutions.net/ + +The project page is http://bcm43xx.berlios.de/ + + +Requirements +------------ + +1) Linux Kernel 2.6.15 or later + http://www.kernel.org/ + + You may want to configure your kernel with: + + CONFIG_DEBUG_FS (optional): + -> Kernel hacking + -> Debug Filesystem + +2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 + modules: + http://softmac.sipsolutions.net/ + +3) Firmware Files + + Please try fwcutter. Fwcutter can extract the firmware from various + binary driver files. It supports driver files from Windows, MacOS and + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. + Also, fwcutter comes with a README file for further instructions. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h new file mode 100644 index 00000000000..aca1601e5b4 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -0,0 +1,961 @@ +#ifndef BCM43xx_H_ +#define BCM43xx_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "bcm43xx_debugfs.h" +#include "bcm43xx_leds.h" + + +#define DRV_NAME __stringify(KBUILD_MODNAME) +#define DRV_VERSION __stringify(BCM43xx_VERSION) +#define BCM43xx_DRIVER_NAME DRV_NAME " driver " DRV_VERSION +#define PFX DRV_NAME ": " + +#define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 +#define BCM43xx_IRQWAIT_MAX_RETRIES 50 +#define BCM43xx_TX_TIMEOUT (10 * HZ) + +#define BCM43xx_IO_SIZE 8192 +#define BCM43xx_REG_ACTIVE_CORE 0x80 + +/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ +#define BCM43xx_PCICFG_ICR 0x94 +/* SPROM control register. */ +#define BCM43xx_PCICFG_SPROMCTL 0x88 + +/* MMIO offsets */ +#define BCM43xx_MMIO_DMA1_REASON 0x20 +#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24 +#define BCM43xx_MMIO_DMA2_REASON 0x28 +#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C +#define BCM43xx_MMIO_DMA3_REASON 0x30 +#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34 +#define BCM43xx_MMIO_DMA4_REASON 0x38 +#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C +#define BCM43xx_MMIO_STATUS_BITFIELD 0x120 +#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 +#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 +#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C +#define BCM43xx_MMIO_RAM_CONTROL 0x130 +#define BCM43xx_MMIO_RAM_DATA 0x134 +#define BCM43xx_MMIO_PS_STATUS 0x140 +#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158 +#define BCM43xx_MMIO_SHM_CONTROL 0x160 +#define BCM43xx_MMIO_SHM_DATA 0x164 +#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166 +#define BCM43xx_MMIO_XMITSTAT_0 0x170 +#define BCM43xx_MMIO_XMITSTAT_1 0x174 +#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ +#define BCM43xx_MMIO_DMA1_BASE 0x200 +#define BCM43xx_MMIO_DMA2_BASE 0x220 +#define BCM43xx_MMIO_DMA3_BASE 0x240 +#define BCM43xx_MMIO_DMA4_BASE 0x260 +#define BCM43xx_MMIO_PIO1_BASE 0x300 +#define BCM43xx_MMIO_PIO2_BASE 0x310 +#define BCM43xx_MMIO_PIO3_BASE 0x320 +#define BCM43xx_MMIO_PIO4_BASE 0x330 +#define BCM43xx_MMIO_PHY_VER 0x3E0 +#define BCM43xx_MMIO_PHY_RADIO 0x3E2 +#define BCM43xx_MMIO_ANTENNA 0x3E8 +#define BCM43xx_MMIO_CHANNEL 0x3F0 +#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4 +#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6 +#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8 +#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA +#define BCM43xx_MMIO_PHY_CONTROL 0x3FC +#define BCM43xx_MMIO_PHY_DATA 0x3FE +#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420 +#define BCM43xx_MMIO_MACFILTER_DATA 0x422 +#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A +#define BCM43xx_MMIO_GPIO_CONTROL 0x49C +#define BCM43xx_MMIO_GPIO_MASK 0x49E +#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM offsets. */ +#define BCM43xx_SPROM_BASE 0x1000 +#define BCM43xx_SPROM_BOARDFLAGS2 0x1c +#define BCM43xx_SPROM_IL0MACADDR 0x24 +#define BCM43xx_SPROM_ET0MACADDR 0x27 +#define BCM43xx_SPROM_ET1MACADDR 0x2a +#define BCM43xx_SPROM_ETHPHY 0x2d +#define BCM43xx_SPROM_BOARDREV 0x2e +#define BCM43xx_SPROM_PA0B0 0x2f +#define BCM43xx_SPROM_PA0B1 0x30 +#define BCM43xx_SPROM_PA0B2 0x31 +#define BCM43xx_SPROM_WL0GPIO0 0x32 +#define BCM43xx_SPROM_WL0GPIO2 0x33 +#define BCM43xx_SPROM_MAXPWR 0x34 +#define BCM43xx_SPROM_PA1B0 0x35 +#define BCM43xx_SPROM_PA1B1 0x36 +#define BCM43xx_SPROM_PA1B2 0x37 +#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38 +#define BCM43xx_SPROM_BOARDFLAGS 0x39 +#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a +#define BCM43xx_SPROM_VERSION 0x3f + +/* BCM43xx_SPROM_BOARDFLAGS values */ +#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ +#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define BCM43xx_GPIO_CONTROL 0x6c + +/* SHM Routing */ +#define BCM43xx_SHM_SHARED 0x0001 +#define BCM43xx_SHM_WIRELESS 0x0002 +#define BCM43xx_SHM_PCM 0x0003 +#define BCM43xx_SHM_HWMAC 0x0004 +#define BCM43xx_SHM_UCODE 0x0300 + +/* MacFilter offsets. */ +#define BCM43xx_MACFILTER_SELF 0x0000 +#define BCM43xx_MACFILTER_ASSOC 0x0003 + +/* Chipcommon registers. */ +#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 +#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 +#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 +#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 +#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0 + +/* PCI core specific registers. */ +#define BCM43xx_PCICORE_BCAST_ADDR 0x50 +#define BCM43xx_PCICORE_BCAST_DATA 0x54 +#define BCM43xx_PCICORE_SBTOPCI2 0x108 + +/* SBTOPCI2 values. */ +#define BCM43xx_SBTOPCI2_PREFETCH 0x4 +#define BCM43xx_SBTOPCI2_BURST 0x8 + +/* Chipcommon capabilities. */ +#define BCM43xx_CAPABILITIES_PCTL 0x00040000 +#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000 +#define BCM43xx_CAPABILITIES_PLLSHIFT 16 +#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700 +#define BCM43xx_CAPABILITIES_FLASHSHIFT 8 +#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040 +#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020 +#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018 +#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3 +#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004 +#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003 + +/* PowerControl */ +#define BCM43xx_PCTL_IN 0xB0 +#define BCM43xx_PCTL_OUT 0xB4 +#define BCM43xx_PCTL_OUTENABLE 0xB8 +#define BCM43xx_PCTL_XTAL_POWERUP 0x40 +#define BCM43xx_PCTL_PLL_POWERDOWN 0x80 + +/* PowerControl Clock Modes */ +#define BCM43xx_PCTL_CLK_FAST 0x00 +#define BCM43xx_PCTL_CLK_SLOW 0x01 +#define BCM43xx_PCTL_CLK_DYNAMIC 0x02 + +#define BCM43xx_PCTL_FORCE_SLOW 0x0800 +#define BCM43xx_PCTL_FORCE_PLL 0x1000 +#define BCM43xx_PCTL_DYN_XTAL 0x2000 + +/* COREIDs */ +#define BCM43xx_COREID_CHIPCOMMON 0x800 +#define BCM43xx_COREID_ILINE20 0x801 +#define BCM43xx_COREID_SDRAM 0x803 +#define BCM43xx_COREID_PCI 0x804 +#define BCM43xx_COREID_MIPS 0x805 +#define BCM43xx_COREID_ETHERNET 0x806 +#define BCM43xx_COREID_V90 0x807 +#define BCM43xx_COREID_USB11_HOSTDEV 0x80a +#define BCM43xx_COREID_IPSEC 0x80b +#define BCM43xx_COREID_PCMCIA 0x80d +#define BCM43xx_COREID_EXT_IF 0x80f +#define BCM43xx_COREID_80211 0x812 +#define BCM43xx_COREID_MIPS_3302 0x816 +#define BCM43xx_COREID_USB11_HOST 0x817 +#define BCM43xx_COREID_USB11_DEV 0x818 +#define BCM43xx_COREID_USB20_HOST 0x819 +#define BCM43xx_COREID_USB20_DEV 0x81a +#define BCM43xx_COREID_SDIO_HOST 0x81b + +/* Core Information Registers */ +#define BCM43xx_CIR_BASE 0xf00 +#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18) +#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90) +#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94) +#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98) +#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c) +#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8) +#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc) + +/* Mask to get the Backplane Flag Number from SBTPSFLAG. */ +#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f + +/* SBIMCONFIGLOW values/masks. */ +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007 +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4 +#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000 +#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16 + +/* sbtmstatelow state flags */ +#define BCM43xx_SBTMSTATELOW_RESET 0x01 +#define BCM43xx_SBTMSTATELOW_REJECT 0x02 +#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 +#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 + +/* sbtmstatehigh state flags */ +#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1 +#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4 + +/* sbimstate flags */ +#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 +#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000 + +/* PHYVersioning */ +#define BCM43xx_PHYTYPE_A 0x00 +#define BCM43xx_PHYTYPE_B 0x01 +#define BCM43xx_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define BCM43xx_PHY_ILT_A_CTRL 0x0072 +#define BCM43xx_PHY_ILT_A_DATA1 0x0073 +#define BCM43xx_PHY_ILT_A_DATA2 0x0074 +#define BCM43xx_PHY_G_LO_CONTROL 0x0810 +#define BCM43xx_PHY_ILT_G_CTRL 0x0472 +#define BCM43xx_PHY_ILT_G_DATA1 0x0473 +#define BCM43xx_PHY_ILT_G_DATA2 0x0474 +#define BCM43xx_PHY_A_PCTL 0x007B +#define BCM43xx_PHY_G_PCTL 0x0029 +#define BCM43xx_PHY_A_CRS 0x0029 +#define BCM43xx_PHY_RADIO_BITFIELD 0x0401 +#define BCM43xx_PHY_G_CRS 0x0429 +#define BCM43xx_PHY_NRSSILT_CTRL 0x0803 +#define BCM43xx_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define BCM43xx_RADIOCTL_ID 0x01 + +/* StatusBitField */ +#define BCM43xx_SBF_MAC_ENABLED 0x00000001 +#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/ +#define BCM43xx_SBF_CORE_READY 0x00000004 +#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/ +#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/ +#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/ +#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000 +#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000 +#define BCM43xx_SBF_MODE_AP 0x00040000 +#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000 +#define BCM43xx_SBF_MODE_MONITOR 0x00400000 +#define BCM43xx_SBF_MODE_PROMISC 0x01000000 +#define BCM43xx_SBF_PS1 0x02000000 +#define BCM43xx_SBF_PS2 0x04000000 +#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 +#define BCM43xx_SBF_TIME_UPDATE 0x10000000 +#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ + +/* MicrocodeFlagsBitfield (addr + lo-word values?)*/ +#define BCM43xx_UCODEFLAGS_OFFSET 0x005E + +#define BCM43xx_UCODEFLAG_AUTODIV 0x0001 +#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002 +#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004 +#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 +#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 +#define BCM43xx_UCODEFLAG_JAPAN 0x0080 + +/* Generic-Interrupt reasons. */ +#define BCM43xx_IRQ_READY (1 << 0) +#define BCM43xx_IRQ_BEACON (1 << 1) +#define BCM43xx_IRQ_PS (1 << 2) +#define BCM43xx_IRQ_REG124 (1 << 5) +#define BCM43xx_IRQ_PMQ (1 << 6) +#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8) +#define BCM43xx_IRQ_XMIT_ERROR (1 << 11) +#define BCM43xx_IRQ_RX (1 << 15) +#define BCM43xx_IRQ_SCAN (1 << 16) +#define BCM43xx_IRQ_NOISE (1 << 18) +#define BCM43xx_IRQ_XMIT_STATUS (1 << 29) + +#define BCM43xx_IRQ_ALL 0xffffffff +#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \ + BCM43xx_IRQ_REG124 | \ + BCM43xx_IRQ_PMQ | \ + BCM43xx_IRQ_XMIT_ERROR | \ + BCM43xx_IRQ_RX | \ + BCM43xx_IRQ_SCAN | \ + BCM43xx_IRQ_NOISE | \ + BCM43xx_IRQ_XMIT_STATUS) + + +/* Initial default iw_mode */ +#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA + +/* Values/Masks for the device TX header */ +#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 +#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 +#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 +#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 +#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 + +#define BCM43xx_TXHDRCTL_OFDM 0x0001 +#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 +#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 +#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 + +#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 +#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 +#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 + +/* Bus type PCI. */ +#define BCM43xx_BUSTYPE_PCI 0 +/* Bus type Silicone Backplane Bus. */ +#define BCM43xx_BUSTYPE_SB 1 +/* Bus type PCMCIA. */ +#define BCM43xx_BUSTYPE_PCMCIA 2 + +/* Threshold values. */ +#define BCM43xx_MIN_RTS_THRESHOLD 1U +#define BCM43xx_MAX_RTS_THRESHOLD 2304U +#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD + +#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7 +#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define BCM43xx_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + BCM43xx_SEC_ALGO_WEP, + BCM43xx_SEC_ALGO_UNKNOWN, + BCM43xx_SEC_ALGO_AES, + BCM43xx_SEC_ALGO_WEP104, + BCM43xx_SEC_ALGO_TKIP, +}; + +#ifdef assert +# undef assert +#endif +#ifdef CONFIG_BCM43XX_DEBUG +#define assert(expr) \ + do { \ + if (unlikely(!(expr))) { \ + printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \ + #expr, __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +#define assert(expr) do { /* nothing */ } while (0) +#endif + +/* rate limited printk(). */ +#ifdef printkl +# undef printkl +#endif +#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) +/* rate limited printk() for debugging */ +#ifdef dprintkl +# undef dprintkl +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintkl printkl +#else +# define dprintkl(f, x...) do { /* nothing */ } while (0) +#endif + +/* Helper macro for if branches. + * An if branch marked with this macro is only taken in DEBUG mode. + * Example: + * if (DEBUG_ONLY(foo == bar)) { + * do something + * } + * In DEBUG mode, the branch will be taken if (foo == bar). + * In non-DEBUG mode, the branch will never be taken. + */ +#ifdef DEBUG_ONLY +# undef DEBUG_ONLY +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define DEBUG_ONLY(x) (x) +#else +# define DEBUG_ONLY(x) 0 +#endif + +/* debugging printk() */ +#ifdef dprintk +# undef dprintk +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintk(f, x...) do { printk(f ,##x); } while (0) +#else +# define dprintk(f, x...) do { /* nothing */ } while (0) +#endif + + +struct net_device; +struct pci_dev; +struct workqueue_struct; +struct bcm43xx_dmaring; +struct bcm43xx_pioqueue; + +struct bcm43xx_initval { + u16 offset; + u16 size; + u32 value; +} __attribute__((__packed__)); + +/* Values for bcm430x_sprominfo.locale */ +enum { + BCM43xx_LOCALE_WORLD = 0, + BCM43xx_LOCALE_THAILAND, + BCM43xx_LOCALE_ISRAEL, + BCM43xx_LOCALE_JORDAN, + BCM43xx_LOCALE_CHINA, + BCM43xx_LOCALE_JAPAN, + BCM43xx_LOCALE_USA_CANADA_ANZ, + BCM43xx_LOCALE_EUROPE, + BCM43xx_LOCALE_USA_LOW, + BCM43xx_LOCALE_JAPAN_HIGH, + BCM43xx_LOCALE_ALL, + BCM43xx_LOCALE_NONE, +}; + +#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */ +struct bcm43xx_sprominfo { + u16 boardflags2; + u8 il0macaddr[6]; + u8 et0macaddr[6]; + u8 et1macaddr[6]; + u8 et0phyaddr:5; + u8 et1phyaddr:5; + u8 et0mdcport:1; + u8 et1mdcport:1; + u8 boardrev; + u8 locale:4; + u8 antennas_aphy:2; + u8 antennas_bgphy:2; + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u8 wl0gpio0; + u8 wl0gpio1; + u8 wl0gpio2; + u8 wl0gpio3; + u8 maxpower_aphy; + u8 maxpower_bgphy; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + u8 idle_tssi_tgt_aphy; + u8 idle_tssi_tgt_bgphy; + u16 boardflags; + u16 antennagain_aphy; + u16 antennagain_bgphy; +}; + +/* Value pair to measure the LocalOscillator. */ +struct bcm43xx_lopair { + s8 low; + s8 high; + u8 used:1; +}; +#define BCM43xx_LO_COUNT (14*4) + +struct bcm43xx_phyinfo { + /* Hardware Data */ + u8 version; + u8 type; + u8 rev; + u16 antenna_diversity; + u16 savedpctlreg; + u16 minlowsig[2]; + u16 minlowsigpos[2]; + u8 connected:1, + calibrated:1, + is_locked:1, /* used in bcm43xx_phy_{un}lock() */ + dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */ + /* LO Measurement Data. + * Use bcm43xx_get_lopair() to get a value. + */ + struct bcm43xx_lopair *_lo_pairs; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* idle TSSI value */ + s8 idle_tssi; + /* PHY lock for core.rev < 3 + * This lock is only used by bcm43xx_phy_{un}lock() + */ + spinlock_t lock; +}; + + +struct bcm43xx_radioinfo { + u16 manufact; + u16 version; + u8 revision; + + /* 0: baseband attenuation, + * 1: radio attenuation, + * 2: tx_CTL1 + * 3: tx_CTL2 + */ + u16 txpower[4]; + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code */ + u16 interfstack[20]; + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + u8 initial_channel; + + u16 lofcal; + + u16 initval; + + u8 enabled:1; + /* ACI (adjacent channel interference) flags. */ + u8 aci_enable:1, + aci_wlan_automatic:1, + aci_hw_rssi:1; +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct bcm43xx_dma { + struct bcm43xx_dmaring *tx_ring0; + struct bcm43xx_dmaring *tx_ring1; + struct bcm43xx_dmaring *tx_ring2; + struct bcm43xx_dmaring *tx_ring3; + struct bcm43xx_dmaring *rx_ring0; + struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct bcm43xx_pio { + struct bcm43xx_pioqueue *queue0; + struct bcm43xx_pioqueue *queue1; + struct bcm43xx_pioqueue *queue2; + struct bcm43xx_pioqueue *queue3; +}; + +#define BCM43xx_MAX_80211_CORES 2 + +#define BCM43xx_COREFLAG_AVAILABLE (1 << 0) +#define BCM43xx_COREFLAG_ENABLED (1 << 1) +#define BCM43xx_COREFLAG_INITIALIZED (1 << 2) + +#ifdef CONFIG_BCM947XX +#define core_offset(bcm) (bcm)->current_core_offset +#else +#define core_offset(bcm) 0 +#endif + +struct bcm43xx_coreinfo { + /** Driver internal flags. See BCM43xx_COREFLAG_* */ + u32 flags; + /** core_id ID number */ + u16 id; + /** core_rev revision number */ + u8 rev; + /** Index number for _switch_core() */ + u8 index; + /* Pointer to the PHYinfo, which belongs to this core (if 80211 core) */ + struct bcm43xx_phyinfo *phy; + /* Pointer to the RadioInfo, which belongs to this core (if 80211 core) */ + struct bcm43xx_radioinfo *radio; + /* Pointer to the DMA rings, which belong to this core (if 80211 core) */ + struct bcm43xx_dma *dma; + /* Pointer to the PIO queues, which belong to this core (if 80211 core) */ + struct bcm43xx_pio *pio; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct bcm43xx_noise_calculation { + struct bcm43xx_coreinfo *core_at_start; + u8 channel_at_start; + u8 calculation_running:1; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct bcm43xx_stats { + u8 link_quality; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct bcm43xx_key { + u8 enabled:1; + u8 algorithm; +}; + +struct bcm43xx_private { + struct ieee80211_device *ieee; + struct ieee80211softmac_device *softmac; + + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned int irq; + + void __iomem *mmio_addr; + unsigned int mmio_len; + + spinlock_t lock; + + /* Driver status flags. */ + u32 initialized:1, /* init_board() succeed */ + was_initialized:1, /* for PCI suspend/resume. */ + shutting_down:1, /* free_board() in progress */ + pio_mode:1, /* PIO (if true), or DMA (if false) used. */ + bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ + reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ + powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ + short_preamble:1, /* TRUE, if short preamble is enabled. */ + firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + + struct bcm43xx_stats stats; + + /* Bus type we are connected to. + * This is currently always BCM43xx_BUSTYPE_PCI + */ + u8 bustype; + + u16 board_vendor; + u16 board_type; + u16 board_revision; + + u16 chip_id; + u8 chip_rev; + + struct bcm43xx_sprominfo sprom; +#define BCM43xx_NR_LEDS 4 + struct bcm43xx_led leds[BCM43xx_NR_LEDS]; + + /* The currently active core. NULL if not initialized, yet. */ + struct bcm43xx_coreinfo *current_core; +#ifdef CONFIG_BCM947XX + /** current core memory offset */ + u32 current_core_offset; +#endif + struct bcm43xx_coreinfo *active_80211_core; + /* coreinfo structs for all possible cores follow. + * Note that a core might not exist. + * So check the coreinfo flags before using it. + */ + struct bcm43xx_coreinfo core_chipcommon; + struct bcm43xx_coreinfo core_pci; + struct bcm43xx_coreinfo core_v90; + struct bcm43xx_coreinfo core_pcmcia; + struct bcm43xx_coreinfo core_ethernet; + struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; + /* Info about the PHY for each 80211 core. */ + struct bcm43xx_phyinfo phy[ BCM43xx_MAX_80211_CORES ]; + /* Info about the Radio for each 80211 core. */ + struct bcm43xx_radioinfo radio[ BCM43xx_MAX_80211_CORES ]; + /* DMA */ + struct bcm43xx_dma dma[ BCM43xx_MAX_80211_CORES ]; + /* PIO */ + struct bcm43xx_pio pio[ BCM43xx_MAX_80211_CORES ]; + + u32 chipcommon_capabilities; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[4]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct bcm43xx_noise_calculation noisecalc; + + /* Threshold values. */ + //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. + u32 rts_threshold; + + /* Interrupt Service Routine tasklet (bottom-half) */ + struct tasklet_struct isr_tasklet; + /* Custom driver work queue. */ + struct workqueue_struct *workqueue; + + /* Periodic tasks */ + struct work_struct periodic_work0; +#define BCM43xx_PERIODIC_0_DELAY (HZ * 15) + struct work_struct periodic_work1; +#define BCM43xx_PERIODIC_1_DELAY ((HZ * 60) + HZ / 2) + struct work_struct periodic_work2; +#define BCM43xx_PERIODIC_2_DELAY ((HZ * 120) + HZ) + struct work_struct periodic_work3; +#define BCM43xx_PERIODIC_3_DELAY ((HZ * 30) + HZ / 5) + + struct work_struct restart_work; + + /* Informational stuff. */ + char nick[IW_ESSID_MAX_SIZE + 1]; + + /* encryption/decryption */ + u16 security_offset; + struct bcm43xx_key key[54]; + u8 default_key_idx; + + /* Firmware. */ + const struct firmware *ucode; + const struct firmware *pcm; + const struct firmware *initvals0; + const struct firmware *initvals1; + + /* Debugging stuff follows. */ +#ifdef CONFIG_BCM43XX_DEBUG + struct bcm43xx_dfsentry *dfsentry; + atomic_t mmio_print_cnt; + atomic_t pcicfg_print_cnt; +#endif +}; + +static inline +struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) +{ + return ieee80211softmac_priv(dev); +} + +static inline +int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) +{ + int i, cnt = 0; + + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + if (bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE) + cnt++; + } + + return cnt; +} + +/* Are we running in init_board() context? */ +static inline +int bcm43xx_is_initializing(struct bcm43xx_private *bcm) +{ + if (bcm->initialized) + return 0; + if (bcm->shutting_down) + return 0; + return 1; +} + +static inline +struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, + u16 radio_attenuation, + u16 baseband_attenuation) +{ + return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2)); +} + + +/* MMIO read/write functions. Debug and non-debug variants. */ +#ifdef CONFIG_BCM43XX_DEBUG + +static inline +u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) +{ + u16 value; + + value = ioread16(bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "ioread16 offset: 0x%04x, value: 0x%04x\n", + offset, value); + } + + return value; +} + +static inline +void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) +{ + iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "iowrite16 offset: 0x%04x, value: 0x%04x\n", + offset, value); + } +} + +static inline +u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) +{ + u32 value; + + value = ioread32(bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "ioread32 offset: 0x%04x, value: 0x%08x\n", + offset, value); + } + + return value; +} + +static inline +void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) +{ + iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "iowrite32 offset: 0x%04x, value: 0x%08x\n", + offset, value); + } +} + +static inline +int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) +{ + int err; + + err = pci_read_config_word(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciread16 offset: 0x%08x, value: 0x%04x, err: %d\n", + offset, *value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) +{ + int err; + + err = pci_read_config_dword(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciread32 offset: 0x%08x, value: 0x%08x, err: %d\n", + offset, *value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) +{ + int err; + + err = pci_write_config_word(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciwrite16 offset: 0x%08x, value: 0x%04x, err: %d\n", + offset, value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) +{ + int err; + + err = pci_write_config_dword(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciwrite32 offset: 0x%08x, value: 0x%08x, err: %d\n", + offset, value, err); + } + + return err; +} + +#define bcm43xx_mmioprint_initial(bcm, value) atomic_set(&(bcm)->mmio_print_cnt, (value)) +#define bcm43xx_mmioprint_enable(bcm) atomic_inc(&(bcm)->mmio_print_cnt) +#define bcm43xx_mmioprint_disable(bcm) atomic_dec(&(bcm)->mmio_print_cnt) +#define bcm43xx_pciprint_initial(bcm, value) atomic_set(&(bcm)->pcicfg_print_cnt, (value)) +#define bcm43xx_pciprint_enable(bcm) atomic_inc(&(bcm)->pcicfg_print_cnt) +#define bcm43xx_pciprint_disable(bcm) atomic_dec(&(bcm)->pcicfg_print_cnt) + +#else /* CONFIG_BCM43XX_DEBUG*/ + +#define bcm43xx_read16(bcm, offset) ioread16((bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_write16(bcm, offset, value) iowrite16((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_read32(bcm, offset) ioread32((bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_write32(bcm, offset, value) iowrite32((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_pci_read_config16(bcm, o, v) pci_read_config_word((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_read_config32(bcm, o, v) pci_read_config_dword((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_write_config16(bcm, o, v) pci_write_config_word((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_write_config32(bcm, o, v) pci_write_config_dword((bcm)->pci_dev, (o), (v)) + +#define bcm43xx_mmioprint_initial(x, y) do { /* nothing */ } while (0) +#define bcm43xx_mmioprint_enable(x) do { /* nothing */ } while (0) +#define bcm43xx_mmioprint_disable(x) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_initial(bcm, value) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_enable(bcm) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_disable(bcm) do { /* nothing */ } while (0) + +#endif /* CONFIG_BCM43XX_DEBUG*/ + + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + + +/* + * Compatibility stuff follows + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) +# error "The bcm43xx driver does not support kernels < 2.6.15" +# error "The driver will _NOT_ compile on your kernel. Please upgrade to the latest 2.6 kernel." +# error "DO NOT COMPLAIN ABOUT BUGS. UPDATE FIRST AND TRY AGAIN." +#else +# if !defined(CONFIG_IEEE80211_MODULE) && !defined(CONFIG_IEEE80211) +# error "Generic IEEE 802.11 Networking Stack (CONFIG_IEEE80211) not available." +# endif +#endif +#ifdef IEEE80211SOFTMAC_API +# if IEEE80211SOFTMAC_API != 0 +# warning "Incompatible SoftMAC subsystem installed." +# endif +#else +# error "The bcm43xx driver requires the SoftMAC subsystem." +# error "SEE >>>>>> http://softmac.sipsolutions.net/ <<<<<<" +#endif + +#endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c new file mode 100644 index 00000000000..f8cfc84ca0d --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -0,0 +1,503 @@ +/* + + Broadcom BCM43xx wireless driver + + debugfs driver debugging code + + Copyright (c) 2005 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + + + +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" + +#define REALLY_BIG_BUFFER_SIZE (1024*256) + +static struct bcm43xx_debugfs fs; +static char really_big_buffer[REALLY_BIG_BUFFER_SIZE]; +static DECLARE_MUTEX(big_buffer_sem); + + +static ssize_t write_file_dummy(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return count; +} + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->u.generic_ip; + return 0; +} + +#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x) + +static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned long flags; + u16 tmp16; + int i; + + down(&big_buffer_sem); + + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + net_dev = bcm->net_dev; + pci_dev = bcm->pci_dev; + + /* This is where the information is written to the "devinfo" file */ + fappend("*** %s devinfo ***\n", net_dev->name); + fappend("vendor: 0x%04x device: 0x%04x\n", + pci_dev->vendor, pci_dev->device); + fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", + pci_dev->subsystem_vendor, pci_dev->subsystem_device); + fappend("IRQ: %d\n", bcm->irq); + fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len); + fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); + if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) + fappend("Radio disabled by hardware!\n"); + if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) + fappend("Radio disabled by hardware!\n"); + fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, + bcm->board_type); + + fappend("\nCores:\n"); +#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ + "rev: 0x%02x, index: 0x%02x\n", \ + (info).flags & BCM43xx_COREFLAG_AVAILABLE \ + ? "available" : "nonavailable", \ + (info).flags & BCM43xx_COREFLAG_ENABLED \ + ? "enabled" : "disabled", \ + (info).id, (info).rev, (info).index) + fappend_core("CHIPCOMMON", bcm->core_chipcommon); + fappend_core("PCI", bcm->core_pci); + fappend_core("V90", bcm->core_v90); + fappend_core("PCMCIA", bcm->core_pcmcia); + fappend_core("ETHERNET", bcm->core_ethernet); + fappend_core("first 80211", bcm->core_80211[0]); + fappend_core("second 80211", bcm->core_80211[1]); +#undef fappend_core + tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + fappend("LEDs: "); + for (i = 0; i < BCM43xx_NR_LEDS; i++) + fappend("%d ", !!(tmp16 & (1 << i))); + fappend("\n"); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + + down(&big_buffer_sem); + + /* This is where the information is written to the "driver" file */ + fappend(BCM43xx_DRIVER_NAME "\n"); + fappend("Compiled at: %s %s\n", __DATE__, __TIME__); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + + /* This is where the information is written to the "sprom_dump" file */ + fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + u64 tsf; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + bcm43xx_tsf_read(bcm, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags; + u64 tsf; + + buf_size = min(count, sizeof (really_big_buffer) - 1); + down(&big_buffer_sem); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_up; + } + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -EFAULT; + goto out_unlock; + } + if (sscanf(buf, "%lli", &tsf) != 1) { + printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); + res = -EINVAL; + goto out_unlock; + } + bcm43xx_tsf_write(bcm, tsf); + res = buf_size; + +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); +out_up: + up(&big_buffer_sem); + return res; +} + +static ssize_t txstat_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *status; + int i, cnt, j = 0; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + + fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", + BCM43xx_NR_LOGGED_XMITSTATUS); + e = bcm->dfsentry; + if (e->xmitstatus_printing == 0) { + /* At the beginning, make a copy of all data to avoid + * concurrency, as this function is called multiple + * times for big logs. Without copying, the data might + * change between reads. This would result in total trash. + */ + e->xmitstatus_printing = 1; + e->saved_xmitstatus_ptr = e->xmitstatus_ptr; + e->saved_xmitstatus_cnt = e->xmitstatus_cnt; + memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer, + BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer))); + } + i = e->saved_xmitstatus_ptr - 1; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + cnt = e->saved_xmitstatus_cnt; + while (cnt) { + status = e->xmitstatus_print_buffer + i; + fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, " + "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, " + "unk: 0x%04x\n", j, + status->cookie, status->flags, + status->cnt1, status->cnt2, status->seq, + status->unknown); + j++; + cnt--; + i--; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + } + + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + spin_lock_irqsave(&bcm->lock, flags); + if (*ppos == pos) { + /* Done. Drop the copied data. */ + e->xmitstatus_printing = 0; + } + spin_unlock_irqrestore(&bcm->lock, flags); + up(&big_buffer_sem); + return res; +} + +#undef fappend + + +static struct file_operations devinfo_fops = { + .read = devinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations spromdump_fops = { + .read = spromdump_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations drvinfo_fops = { + .read = drvinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations tsf_fops = { + .read = tsf_read_file, + .write = tsf_write_file, + .open = open_file_generic, +}; + +static struct file_operations txstat_fops = { + .read = txstat_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + + +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + char devdir[IFNAMSIZ]; + + assert(bcm); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + printk(KERN_ERR PFX "out of memory\n"); + return; + } + e->bcm = bcm; + e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_print_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + + + bcm->dfsentry = e; + + strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir)); + e->subdir = debugfs_create_dir(devdir, fs.root); + e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir, + bcm, &devinfo_fops); + if (!e->dentry_devinfo) + printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir); + e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir, + bcm, &spromdump_fops); + if (!e->dentry_spromdump) + printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir); + e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, + bcm, &tsf_fops); + if (!e->dentry_tsf) + printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); + e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, + bcm, &txstat_fops); + if (!e->dentry_txstat) + printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); +} + +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + + if (!bcm) + return; + + e = bcm->dfsentry; + assert(e); + debugfs_remove(e->dentry_spromdump); + debugfs_remove(e->dentry_devinfo); + debugfs_remove(e->dentry_tsf); + debugfs_remove(e->dentry_txstat); + debugfs_remove(e->subdir); + kfree(e->xmitstatus_buffer); + kfree(e->xmitstatus_print_buffer); + kfree(e); +} + +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *savedstatus; + + /* This is protected by bcm->lock */ + e = bcm->dfsentry; + assert(e); + savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; + memcpy(savedstatus, status, sizeof(*status)); + e->xmitstatus_ptr++; + if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_ptr = 0; + if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_cnt++; +} + +void bcm43xx_debugfs_init(void) +{ + memset(&fs, 0, sizeof(fs)); + fs.root = debugfs_create_dir(DRV_NAME, NULL); + if (!fs.root) + printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "\" subdir failed!\n"); + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); + if (!fs.dentry_driverinfo) + printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "/driver\" failed!\n"); +} + +void bcm43xx_debugfs_exit(void) +{ + debugfs_remove(fs.dentry_driverinfo); + debugfs_remove(fs.root); +} + +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ + size_t i; + char c; + + printk(KERN_INFO PFX "Data dump (%s, %u bytes):", + description, size); + for (i = 0; i < size; i++) { + c = data[i]; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); + else + printk("0x%02x, ", c & 0xff); + } + printk("\n"); +} + +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ + size_t i; + int j; + const unsigned char *d; + + printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", + description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); + for (i = 0; i < bytes; i++) { + d = data + i; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: ", i); + if (msb_to_lsb) { + for (j = 7; j >= 0; j--) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } else { + for (j = 0; j < 8; j++) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } + printk(" "); + } + printk("\n"); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h new file mode 100644 index 00000000000..50ce267f794 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h @@ -0,0 +1,117 @@ +#ifndef BCM43xx_DEBUGFS_H_ +#define BCM43xx_DEBUGFS_H_ + +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + +#ifdef CONFIG_BCM43XX_DEBUG + +#include +#include + +struct dentry; + +/* limited by the size of the "really_big_buffer" */ +#define BCM43xx_NR_LOGGED_XMITSTATUS 100 + +struct bcm43xx_dfsentry { + struct dentry *subdir; + struct dentry *dentry_devinfo; + struct dentry *dentry_spromdump; + struct dentry *dentry_tsf; + struct dentry *dentry_txstat; + + struct bcm43xx_private *bcm; + + /* saved xmitstatus. */ + struct bcm43xx_xmitstatus *xmitstatus_buffer; + int xmitstatus_ptr; + int xmitstatus_cnt; + /* We need a seperate buffer while printing to avoid + * concurrency issues. (New xmitstatus can arrive + * while we are printing). + */ + struct bcm43xx_xmitstatus *xmitstatus_print_buffer; + int saved_xmitstatus_ptr; + int saved_xmitstatus_cnt; + int xmitstatus_printing; +}; + +struct bcm43xx_debugfs { + struct dentry *root; + struct dentry *dentry_driverinfo; +}; + +void bcm43xx_debugfs_init(void); +void bcm43xx_debugfs_exit(void); +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); + +/* Debug helper: Dump binary data through printk. */ +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description); +/* Debug helper: Dump bitwise binary data through printk. */ +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description); +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \ + do { \ + bcm43xx_printk_bitdump((const unsigned char *)(pointer), \ + sizeof(*(pointer)), \ + (msb_to_lsb), \ + (description)); \ + } while (0) + +#else /* CONFIG_BCM43XX_DEBUG*/ + +static inline +void bcm43xx_debugfs_init(void) { } +static inline +void bcm43xx_debugfs_exit(void) { } +static inline +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { } + +static inline +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ +} +static inline +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ +} +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0) + +#endif /* CONFIG_BCM43XX_DEBUG*/ + +/* Ugly helper macros to make incomplete code more verbose on runtime */ +#ifdef TODO +# undef TODO +#endif +#define TODO() \ + do { \ + printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#ifdef FIXME +# undef FIXME +#endif +#define FIXME() \ + do { \ + printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#endif /* BCM43xx_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c new file mode 100644 index 00000000000..df19fbfa9ea --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -0,0 +1,1009 @@ +/* + + Broadcom BCM43xx wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_power.h" + +#include +#include +#include +#include +#include + + +static inline int free_slots(struct bcm43xx_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= -1 && slot <= ring->nr_slots - 1); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= 0 && slot <= ring->nr_slots - 1); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +/* Request a slot for usage. */ +static inline +int request_slot(struct bcm43xx_dmaring *ring) +{ + int slot; + + assert(ring->tx); + assert(!ring->suspended); + assert(free_slots(ring) != 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + /* Check the number of available slots and suspend TX, + * if we are running low on free slots. + */ + if (unlikely(free_slots(ring) < ring->suspend_mark)) { + netif_stop_queue(ring->bcm->net_dev); + ring->suspended = 1; + } +#ifdef CONFIG_BCM43XX_DEBUG + if (ring->used_slots > ring->max_used_slots) + ring->max_used_slots = ring->used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ + + return slot; +} + +/* Return a slot to the free slots. */ +static inline +void return_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(ring->tx); + + ring->used_slots--; + + /* Check if TX is suspended and check if we have + * enough free slots to resume it again. + */ + if (unlikely(ring->suspended)) { + if (free_slots(ring) >= ring->resume_mark) { + ring->suspended = 0; + netif_wake_queue(ring->bcm->net_dev); + } + } +} + +static inline +dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, + unsigned char *buf, + size_t len, + int tx) +{ + dma_addr_t dmaaddr; + + if (tx) { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_TO_DEVICE); + } else { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_FROM_DEVICE); + } + + return dmaaddr; +} + +static inline +void unmap_descbuffer(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len, + int tx) +{ + if (tx) { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_TO_DEVICE); + } else { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_FROM_DEVICE); + } +} + +static inline +void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_device(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void mark_skb_mustfree(struct sk_buff *skb, + char mustfree) +{ + skb->cb[0] = mustfree; +} + +static inline +int skb_mustfree(struct sk_buff *skb) +{ + return (skb->cb[0] != 0); +} + +/* Unmap and free a descriptor buffer. */ +static inline +void free_descriptor_buffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + int irq_context) +{ + assert(meta->skb); + if (skb_mustfree(meta->skb)) { + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); + } + meta->skb = NULL; + if (meta->txb) { + ieee80211_txb_free(meta->txb); + meta->txb = NULL; + } +} + +static int alloc_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->vbase) { + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); + return -ENOMEM; + } + if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G\n"); + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); + return -ENOMEM; + } + assert(!(ring->dmabase & 0x000003FF)); + memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_RX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_RX_STATUS); + value &= BCM43xx_DMA_RXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); + return -ENODEV; + } + + return 0; +} + +static inline int dmacontroller_rx_reset(struct bcm43xx_dmaring *ring) +{ + assert(!ring->tx); + + return bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED || + value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT || + value == BCM43xx_DMA_TXSTAT_STAT_STOPPED) + break; + udelay(10); + } + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_TX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + udelay(300); + + return 0; +} + +static inline int dmacontroller_tx_reset(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + + return bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); +} + +static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + gfp_t gfp_flags) +{ + struct bcm43xx_rxhdr *rxhdr; + dma_addr_t dmaaddr; + u32 desc_addr; + u32 desc_ctl; + const int slot = (int)(desc - ring->vbase); + struct sk_buff *skb; + + assert(slot >= 0 && slot < ring->nr_slots); + assert(!ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb_any(skb); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G\n"); + return -ENOMEM; + } + meta->skb = skb; + meta->dmaaddr = dmaaddr; + skb->dev = ring->bcm->net_dev; + mark_skb_mustfree(skb, 1); + desc_addr = (u32)(dmaaddr + ring->memoffset); + desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(ring->rx_buffersize - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + set_desc_addr(desc, desc_addr); + set_desc_ctl(desc, desc_ctl); + + rxhdr = (struct bcm43xx_rxhdr *)(skb->data); + rxhdr->frame_length = 0; + rxhdr->flags1 = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) +{ + int i, err = -ENOMEM; + struct bcm43xx_dmadesc *desc = NULL; + struct bcm43xx_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) + goto err_unwind; + + assert(ring->used_slots <= ring->nr_slots); + } + ring->used_slots = ring->nr_slots; + + err = 0; +out: + return err; + +err_unwind: + for ( ; i >= 0; i--) { + desc = ring->vbase + i; + meta = ring->meta + i; + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + ring->used_slots = 0; + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct bcm43xx_dmaring *ring) +{ + int err = 0; + u32 value; + + if (ring->tx) { + /* Set Transmit Control register to "transmit enable" */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_CONTROL, + BCM43xx_DMA_TXCTRL_ENABLE); + /* Set Transmit Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, + ring->dmabase + ring->memoffset); + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + /* Set Receive Control "receive enable" and frame offset */ + value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); + value |= BCM43xx_DMA_RXCTRL_ENABLE; + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_CONTROL, + value); + /* Set Receive Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, + ring->dmabase + ring->memoffset); + /* Init the descriptor pointer. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, + 200); + } + +out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) +{ + if (ring->tx) { + dmacontroller_tx_reset(ring); + /* Zero out Transmit Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, + 0x00000000); + } else { + dmacontroller_rx_reset(ring); + /* Zero out Receive Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, + 0x00000000); + } +} + +static void free_all_descbuffers(struct bcm43xx_dmaring *ring) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + if (!meta->skb) { + assert(ring->tx); + assert(!meta->txb); + continue; + } + if (ring->tx) { + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + } else { + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + } + free_descriptor_buffer(ring, desc, meta, 0); + } +} + +/* Main initialization function. */ +static +struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, + u16 dma_controller_base, + int nr_descriptor_slots, + int tx) +{ + struct bcm43xx_dmaring *ring; + int err; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots, + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + + ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + ring->memoffset = 0; +#endif + + + spin_lock_init(&ring->lock); + ring->bcm = bcm; + ring->nr_slots = nr_descriptor_slots; + ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; + ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; + assert(ring->suspend_mark < ring->resume_mark); + ring->mmio_base = dma_controller_base; + if (tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + switch (dma_controller_base) { + case BCM43xx_MMIO_DMA1_BASE: + ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET; + break; + case BCM43xx_MMIO_DMA4_BASE: + ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET; + break; + default: + assert(0); + } + } + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_meta; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + +out: + return ring; + +err_free_ringmemory: + free_ringmemory(ring); +err_kfree_meta: + kfree(ring->meta); +err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) +{ + if (!ring) + return; + + dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n", + ring->mmio_base, + (ring->tx) ? "TX" : "RX", + ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->meta); + kfree(ring); +} + +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring1); + bcm->current_core->dma->rx_ring1 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); + bcm->current_core->dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); + bcm->current_core->dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); + bcm->current_core->dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); + bcm->current_core->dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); + bcm->current_core->dma->tx_ring0 = NULL; +} + +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dmaring *ring; + int err = -ENOMEM; + + /* setup TX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto out; + bcm->current_core->dma->tx_ring0 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx0; + bcm->current_core->dma->tx_ring1 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx1; + bcm->current_core->dma->tx_ring2 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx2; + bcm->current_core->dma->tx_ring3 = ring; + + /* setup RX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_tx3; + bcm->current_core->dma->rx_ring0 = ring; + + if (bcm->current_core->rev < 5) { + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_rx0; + bcm->current_core->dma->rx_ring1 = ring; + } + + dprintk(KERN_INFO PFX "DMA initialized\n"); + err = 0; +out: + return err; + +err_destroy_rx0: + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); + bcm->current_core->dma->rx_ring0 = NULL; +err_destroy_tx3: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); + bcm->current_core->dma->tx_ring3 = NULL; +err_destroy_tx2: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); + bcm->current_core->dma->tx_ring2 = NULL; +err_destroy_tx1: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); + bcm->current_core->dma->tx_ring1 = NULL; +err_destroy_tx0: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); + bcm->current_core->dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static inline +u16 generate_cookie(struct bcm43xx_dmaring *ring, + int slot) +{ + u16 cookie = 0x0000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits + */ + switch (ring->mmio_base) { + default: + assert(0); + case BCM43xx_MMIO_DMA1_BASE: + break; + case BCM43xx_MMIO_DMA2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_DMA3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_DMA4_BASE: + cookie = 0x3000; + break; + } + assert(((u16)slot & 0xF000) == 0x0000); + cookie |= (u16)slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static inline +struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, int *slot) +{ + struct bcm43xx_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0x0000: + ring = bcm->current_core->dma->tx_ring0; + break; + case 0x1000: + ring = bcm->current_core->dma->tx_ring1; + break; + case 0x2000: + ring = bcm->current_core->dma->tx_ring2; + break; + case 0x3000: + ring = bcm->current_core->dma->tx_ring3; + break; + default: + assert(0); + } + *slot = (cookie & 0x0FFF); + assert(*slot >= 0 && *slot < ring->nr_slots); + + return ring; +} + +static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, + int slot) +{ + /* Everything is ready to start. Buffers are DMA mapped and + * associated with slots. + * "slot" is the last slot of the new frame we want to transmit. + * Close your seat belts now, please. + */ + wmb(); + slot = next_slot(ring, slot); + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); +} + +static inline +int dma_tx_fragment(struct bcm43xx_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_txb *txb, + u8 cur_frag) +{ + int slot; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + u32 desc_ctl; + u32 desc_addr; + + assert(skb_shinfo(skb)->nr_frags == 0); + + slot = request_slot(ring); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + if (cur_frag == 0) { + /* Save the txb pointer for freeing in xmitstatus IRQ */ + meta->txb = txb; + } + + /* Add a device specific TX header. */ + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); + /* Reserve enough headroom for the device tx header. */ + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); + /* Now calculate and add the tx header. + * The tx header includes the PLCP header. + */ + bcm43xx_generate_txhdr(ring->bcm, + (struct bcm43xx_txhdr *)skb->data, + skb->data + sizeof(struct bcm43xx_txhdr), + skb->len - sizeof(struct bcm43xx_txhdr), + (cur_frag == 0), + generate_cookie(ring, slot)); + + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { + return_slot(ring, slot); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G\n"); + return -ENOMEM; + } + + desc_addr = (u32)(meta->dmaaddr + ring->memoffset); + desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND; + desc_ctl |= BCM43xx_DMADTOR_COMPIRQ; + desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(meta->skb->len - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + + set_desc_ctl(desc, desc_ctl); + set_desc_addr(desc, desc_addr); + /* Now transfer the whole frame. */ + dmacontroller_poke_tx(ring, slot); + + return 0; +} + +static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, + struct ieee80211_txb *txb) +{ + /* We just received a packet from the kernel network subsystem. + * Add headers and DMA map the memory. Poke + * the device to send the stuff. + * Note that this is called from atomic context. + */ + u8 i; + struct sk_buff *skb; + + assert(ring->tx); + if (unlikely(free_slots(ring) < txb->nr_frags)) { + /* The queue should be stopped, + * if we are low on free slots. + * If this ever triggers, we have to lower the suspend_mark. + */ + dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n"); + return -ENOMEM; + } + + assert(irqs_disabled()); + spin_lock(&ring->lock); + for (i = 0; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + /* We do not free the skb, as it is freed as + * part of the txb freeing. + */ + mark_skb_mustfree(skb, 0); + dma_tx_fragment(ring, skb, txb, i); + //TODO: handle failure of dma_tx_fragment + } + spin_unlock(&ring->lock); + + return 0; +} + +int fastcall +bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return dma_transfer_txb(bcm->current_core->dma->tx_ring1, + txb); +} + +void fastcall +bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dmaring *ring; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int is_last_fragment; + int slot; + + ring = parse_cookie(bcm, status->cookie, &slot); + assert(ring); + assert(ring->tx); + assert(irqs_disabled()); + spin_lock(&ring->lock); + + assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); + while (1) { + assert(slot >= 0 && slot < ring->nr_slots); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND); + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); + free_descriptor_buffer(ring, desc, meta, 1); + /* Everything belonging to the slot is unmapped + * and freed, so we can return it. + */ + return_slot(ring, slot); + + if (is_last_fragment) + break; + slot = next_slot(ring, slot); + } + bcm->stats.last_tx = jiffies; + + spin_unlock(&ring->lock); +} + +static inline +void dma_rx(struct bcm43xx_dmaring *ring, + int *slot) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + struct bcm43xx_rxhdr *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) { + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; + struct bcm43xx_xmitstatus stat; + + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(ring->bcm, &stat); + bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); + + return; + } + rxhdr = (struct bcm43xx_rxhdr *)skb->data; + len = le16_to_cpu(rxhdr->frame_length); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_length); + } while (len == 0 && i++ < 5); + if (len == 0) + goto drop; + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 1; + s32 tmp = len - ring->rx_buffersize; + + for ( ; tmp > 0; tmp -= ring->rx_buffersize) { + *slot = next_slot(ring, *slot); + cnt++; + } + printkl(KERN_ERR PFX "DMA RX buffer too small. %d dropped.\n", + cnt); + goto drop; + } + len -= IEEE80211_FCS_LEN; + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + err = bcm43xx_rx(ring->bcm, skb, rxhdr); + if (err) { + dev_kfree_skb_irq(skb); + goto drop; + } + +drop: + return; +} + +void fastcall +bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ + u32 status; + u16 descptr; + int slot, current_slot; +#ifdef CONFIG_BCM43XX_DEBUG + int used_slots = 0; +#endif + + assert(!ring->tx); + assert(irqs_disabled()); + spin_lock(&ring->lock); + + status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); + descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); + current_slot = descptr / sizeof(struct bcm43xx_dmadesc); + assert(current_slot >= 0 && current_slot < ring->nr_slots); + + slot = ring->current_slot; + for ( ; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); +#ifdef CONFIG_BCM43XX_DEBUG + if (++used_slots > ring->max_used_slots) + ring->max_used_slots = used_slots; +#endif + } + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + ring->current_slot = slot; + + spin_unlock(&ring->lock); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h new file mode 100644 index 00000000000..e32cf68f8e1 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -0,0 +1,176 @@ +#ifndef BCM43xx_DMA_H_ +#define BCM43xx_DMA_H_ + +#include +#include +#include +#include +#include + + +/* DMA-Interrupt reasons. */ +/*TODO: add the missing ones. */ +#define BCM43xx_DMAIRQ_ERR0 (1 << 10) +#define BCM43xx_DMAIRQ_ERR1 (1 << 11) +#define BCM43xx_DMAIRQ_ERR2 (1 << 12) +#define BCM43xx_DMAIRQ_ERR3 (1 << 13) +#define BCM43xx_DMAIRQ_ERR4 (1 << 14) +#define BCM43xx_DMAIRQ_ERR5 (1 << 15) +#define BCM43xx_DMAIRQ_RX_DONE (1 << 16) +/* helpers */ +#define BCM43xx_DMAIRQ_ANYERR (BCM43xx_DMAIRQ_ERR0 | \ + BCM43xx_DMAIRQ_ERR1 | \ + BCM43xx_DMAIRQ_ERR2 | \ + BCM43xx_DMAIRQ_ERR3 | \ + BCM43xx_DMAIRQ_ERR4 | \ + BCM43xx_DMAIRQ_ERR5) +#define BCM43xx_DMAIRQ_FATALERR (BCM43xx_DMAIRQ_ERR0 | \ + BCM43xx_DMAIRQ_ERR1 | \ + BCM43xx_DMAIRQ_ERR2 | \ + BCM43xx_DMAIRQ_ERR4 | \ + BCM43xx_DMAIRQ_ERR5) +#define BCM43xx_DMAIRQ_NONFATALERR BCM43xx_DMAIRQ_ERR3 + +/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ +#define BCM43xx_DMA_TX_CONTROL 0x00 +#define BCM43xx_DMA_TX_DESC_RING 0x04 +#define BCM43xx_DMA_TX_DESC_INDEX 0x08 +#define BCM43xx_DMA_TX_STATUS 0x0c +#define BCM43xx_DMA_RX_CONTROL 0x10 +#define BCM43xx_DMA_RX_DESC_RING 0x14 +#define BCM43xx_DMA_RX_DESC_INDEX 0x18 +#define BCM43xx_DMA_RX_STATUS 0x1c + +/* DMA controller channel control word values. */ +#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1) +#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2) +#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4) +#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1 +#define BCM43xx_DMA_RXCTRL_PIO (1 << 8) +/* DMA controller channel status word values. */ +#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000 +#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000 +#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000 +#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20) +#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000 +#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000 +#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000 + +/* DMA descriptor control field values. */ +#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff +#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */ +#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */ +#define BCM43xx_DMADTOR_FRAMEEND (1 << 30) +#define BCM43xx_DMADTOR_FRAMESTART (1 << 31) + +/* Misc DMA constants */ +#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE +#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF +#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30) +#define BCM43xx_DMA1_RX_FRAMEOFFSET 30 +#define BCM43xx_DMA4_RX_FRAMEOFFSET 0 + +/* DMA engine tuning knobs */ +#define BCM43xx_TXRING_SLOTS 512 +#define BCM43xx_RXRING_SLOTS 64 +#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100) +#define BCM43xx_DMA4_RXBUFFERSIZE 16 +/* Suspend the tx queue, if less than this percent slots are free. */ +#define BCM43xx_TXSUSPEND_PERCENT 20 +/* Resume the tx queue, if more than this percent slots are free. */ +#define BCM43xx_TXRESUME_PERCENT 50 + + +struct sk_buff; +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + + +struct bcm43xx_dmadesc { + __le32 _control; + __le32 _address; +} __attribute__((__packed__)); + +/* Macros to access the bcm43xx_dmadesc struct */ +#define get_desc_ctl(desc) le32_to_cpu((desc)->_control) +#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0) +#define get_desc_addr(desc) le32_to_cpu((desc)->_address) +#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0) + +struct bcm43xx_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* Pointer to our txb (can be NULL). + * This should be freed in completion IRQ. + */ + struct ieee80211_txb *txb; +}; + +struct bcm43xx_dmaring { + spinlock_t lock; + struct bcm43xx_private *bcm; + /* Kernel virtual base address of the ring memory. */ + struct bcm43xx_dmadesc *vbase; + /* DMA memory offset */ + dma_addr_t memoffset; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Meta data about all descriptors. */ + struct bcm43xx_dmadesc_meta *meta; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Marks to suspend/resume the queue. */ + int suspend_mark; + int resume_mark; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller, this + * ring is posted to. + */ + u16 mmio_base; + u8 tx:1, /* TRUE, if this is a TX ring. */ + suspended:1; /* TRUE, if transfers are suspended on this ring. */ +#ifdef CONFIG_BCM43XX_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ +}; + + +int bcm43xx_dma_init(struct bcm43xx_private *bcm); +void bcm43xx_dma_free(struct bcm43xx_private *bcm); + +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); + +int FASTCALL(bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb)); +void FASTCALL(bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status)); + +void FASTCALL(bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)); + +#endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c new file mode 100644 index 00000000000..22587e0e1a0 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -0,0 +1,367 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_phy.h" + + +/**** Initial Internal Lookup Tables ****/ + +const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +/**** Helper functions to access the device Internal Lookup Tables ****/ + +void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); + } +} + +u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); + } +} + +void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (u16)(val >> 16)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, (u16)(val & 0x0000FFFF)); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (u16)(val >> 16)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, (u16)(val & 0x0000FFFF)); + } +} + +u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset) +{ + u32 ret; + + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA2); + ret <<= 16; + ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA2); + ret <<= 16; + ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); + } + + return ret; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h new file mode 100644 index 00000000000..d92527fd83e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h @@ -0,0 +1,34 @@ +#ifndef BCM43xx_ILT_H_ +#define BCM43xx_ILT_H_ + +#define BCM43xx_ILT_ROTOR_SIZE 53 +extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE]; +#define BCM43xx_ILT_RETARD_SIZE 53 +extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE]; +#define BCM43xx_ILT_FINEFREQA_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE]; +#define BCM43xx_ILT_FINEFREQG_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE]; +#define BCM43xx_ILT_NOISEA2_SIZE 8 +extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE]; +#define BCM43xx_ILT_NOISEA3_SIZE 8 +extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE]; +#define BCM43xx_ILT_NOISEG1_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE]; +#define BCM43xx_ILT_NOISEG2_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE]; +#define BCM43xx_ILT_NOISESCALEG_SIZE 27 +extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE]; +#define BCM43xx_ILT_SIGMASQR_SIZE 53 +extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; +extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; + + +void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); +u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); +u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset); + +#endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c new file mode 100644 index 00000000000..455a0c743f7 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -0,0 +1,261 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_leds.h" +#include "bcm43xx.h" + +#include + + +static void bcm43xx_led_changestate(struct bcm43xx_led *led) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + u16 ledctl; + + assert(index >= 0 && index < BCM43xx_NR_LEDS); + assert(led->blink_interval); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + __change_bit(index, (unsigned long *)(&ledctl)); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +static void bcm43xx_led_blink(unsigned long d) +{ + struct bcm43xx_led *led = (struct bcm43xx_led *)d; + struct bcm43xx_private *bcm = led->bcm; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (led->blink_interval) { + bcm43xx_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_led_blink_start(struct bcm43xx_led *led, + unsigned long interval) +{ + led->blink_interval = interval; + bcm43xx_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + assert(index >= 0 && index < BCM43xx_NR_LEDS); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +int bcm43xx_leds_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + u8 sprom[4]; + int i; + + sprom[0] = bcm->sprom.wl0gpio0; + sprom[1] = bcm->sprom.wl0gpio1; + sprom[2] = bcm->sprom.wl0gpio2; + sprom[3] = bcm->sprom.wl0gpio3; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + led->bcm = bcm; + init_timer(&led->blink_timer); + led->blink_timer.data = (unsigned long)led; + led->blink_timer.function = bcm43xx_led_blink; + + if (sprom[i] == 0xFF) { + /* SPROM information not set. */ + switch (i) { + case 0: + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = BCM43xx_LED_RADIO_ALL; + else + led->behaviour = BCM43xx_LED_ACTIVITY; + break; + case 1: + led->behaviour = BCM43xx_LED_RADIO_B; + break; + case 2: + led->behaviour = BCM43xx_LED_RADIO_A; + break; + case 3: + led->behaviour = BCM43xx_LED_OFF; + break; + default: + assert(0); + } + } else { + led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); + } + } + + return 0; +} + +void bcm43xx_leds_exit(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + int i; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + bcm43xx_led_blink_stop(led, 1); + } + bcm43xx_leds_turn_off(bcm); +} + +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) +{ + struct bcm43xx_led *led; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; + int i, turn_on = 0; + unsigned long interval = 0; + u16 ledctl; + + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + if (led->behaviour == BCM43xx_LED_INACTIVE) + continue; + + switch (led->behaviour) { + case BCM43xx_LED_OFF: + turn_on = 0; + break; + case BCM43xx_LED_ON: + turn_on = 1; + break; + case BCM43xx_LED_ACTIVITY: + turn_on = activity; + break; + case BCM43xx_LED_RADIO_ALL: + turn_on = radio->enabled; + break; + case BCM43xx_LED_RADIO_A: + turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); + break; + case BCM43xx_LED_RADIO_B: + turn_on = (radio->enabled && + (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G)); + break; + case BCM43xx_LED_MODE_BG: + turn_on = 0; + if (phy->type == BCM43xx_PHYTYPE_G && + 1/*FIXME: using G rates.*/) + turn_on = 1; + break; + case BCM43xx_LED_TRANSFER: + if (transferring) + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_APTRANSFER: + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + if (transferring) { + interval = BCM43xx_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (0/*TODO: not assoc*/) + interval = BCM43xx_LEDBLINK_SLOW; + else if (transferring) + interval = BCM43xx_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + bcm43xx_led_blink_start(led, interval); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_WEIRD: + //TODO + turn_on = 0; + break; + case BCM43xx_LED_ASSOC: + if (1/*TODO: associated*/) + turn_on = 1; + break; + default: + assert(0); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + u16 ledctl = 0; + int i; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + if (led->behaviour == BCM43xx_LED_INACTIVE) + continue; + if (led->activelow) + ledctl |= (1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h new file mode 100644 index 00000000000..489a2b1e906 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -0,0 +1,47 @@ +#ifndef BCM43xx_LEDS_H_ +#define BCM43xx_LEDS_H_ + +#include +#include + + +struct bcm43xx_led { + u8 behaviour:7; + u8 activelow:1; + + struct bcm43xx_private *bcm; + struct timer_list blink_timer; + unsigned long blink_interval; +}; +#define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) + +/* Delay between state changes when blinking in jiffies */ +#define BCM43xx_LEDBLINK_SLOW (HZ / 2) +#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) +#define BCM43xx_LEDBLINK_FAST (HZ / 8) + +#define BCM43xx_LED_XFER_THRES (HZ / 100) + +#define BCM43xx_LED_BEHAVIOUR 0x7F +#define BCM43xx_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + BCM43xx_LED_OFF, + BCM43xx_LED_ON, + BCM43xx_LED_ACTIVITY, + BCM43xx_LED_RADIO_ALL, + BCM43xx_LED_RADIO_A, + BCM43xx_LED_RADIO_B, + BCM43xx_LED_MODE_BG, + BCM43xx_LED_TRANSFER, + BCM43xx_LED_APTRANSFER, + BCM43xx_LED_WEIRD,//FIXME + BCM43xx_LED_ASSOC, + BCM43xx_LED_INACTIVE, +}; + +int bcm43xx_leds_init(struct bcm43xx_private *bcm); +void bcm43xx_leds_exit(struct bcm43xx_private *bcm); +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); +void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c new file mode 100644 index 00000000000..be60a6509f2 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -0,0 +1,4597 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_power.h" +#include "bcm43xx_wx.h" + + +MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_BCM947XX +extern char *nvram_get(char *name); +#endif + +/* Module parameters */ +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); + +static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_locale = -1; +module_param_named(locale, modparam_locale, int, 0444); +MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); + +static int modparam_outdoor; +module_param_named(outdoor, modparam_outdoor, int, 0444); +MODULE_PARM_DESC(outdoor, "Set to 1, if you are using the device outdoor, 0 otherwise."); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +#ifdef CONFIG_BCM43XX_DEBUG +static char modparam_fwpostfix[64]; +module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); +#else +# define modparam_fwpostfix "" +#endif /* CONFIG_BCM43XX_DEBUG*/ + + +/* If you want to debug with just a single device, enable this, + * where the string is the pci device ID (as given by the kernel's + * pci_name function) of the device to be used. + */ +//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0" + +/* If you want to enable printing of each MMIO access, enable this. */ +//#define DEBUG_ENABLE_MMIO_PRINT + +/* If you want to enable printing of MMIO access within + * ucode/pcm upload, initvals write, enable this. + */ +//#define DEBUG_ENABLE_UCODE_MMIO_PRINT + +/* If you want to enable printing of PCI Config Space access, enable this */ +//#define DEBUG_ENABLE_PCILOG + + +static struct pci_device_id bcm43xx_pci_tbl[] = { + + /* Detailed list maintained at: + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices + */ + +#ifdef CONFIG_BCM947XX + /* SB bus on BCM947xx */ + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + + /* Broadcom 4303 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4307 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4318 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4306 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4306 802.11a */ +// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4309 802.11a/b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 43XG 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* required last entry */ + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); + +static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) + val = swab32(val); + + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); +} + +static inline +void bcm43xx_shm_control_word(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control); +} + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u16 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, + value & 0xffff); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + value); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (bcm->current_core->rev >= 3) { + u32 low, high, high2; + + do { + high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); + high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0, v1, v2, v3; + u16 test1, test2, test3; + + do { + v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); + + test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (bcm->current_core->rev >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + barrier(); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + barrier(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); + } + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); +} + +static inline +u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, + const int ofdm_modulation) +{ + u8 rate; + + if (ofdm_modulation) { + switch (plcp->raw[0] & 0xF) { + case 0xB: + rate = IEEE80211_OFDM_RATE_6MB; + break; + case 0xF: + rate = IEEE80211_OFDM_RATE_9MB; + break; + case 0xA: + rate = IEEE80211_OFDM_RATE_12MB; + break; + case 0xE: + rate = IEEE80211_OFDM_RATE_18MB; + break; + case 0x9: + rate = IEEE80211_OFDM_RATE_24MB; + break; + case 0xD: + rate = IEEE80211_OFDM_RATE_36MB; + break; + case 0x8: + rate = IEEE80211_OFDM_RATE_48MB; + break; + case 0xC: + rate = IEEE80211_OFDM_RATE_54MB; + break; + default: + rate = 0; + assert(0); + } + } else { + switch (plcp->raw[0]) { + case 0x0A: + rate = IEEE80211_CCK_RATE_1MB; + break; + case 0x14: + rate = IEEE80211_CCK_RATE_2MB; + break; + case 0x37: + rate = IEEE80211_CCK_RATE_5MB; + break; + case 0x6E: + rate = IEEE80211_CCK_RATE_11MB; + break; + default: + rate = 0; + assert(0); + } + } + + return rate; +} + +static inline +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return 0x0A; + case IEEE80211_CCK_RATE_2MB: + return 0x14; + case IEEE80211_CCK_RATE_5MB: + return 0x37; + case IEEE80211_CCK_RATE_11MB: + return 0x6E; + } + assert(0); + return 0; +} + +static inline +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_OFDM_RATE_6MB: + return 0xB; + case IEEE80211_OFDM_RATE_9MB: + return 0xF; + case IEEE80211_OFDM_RATE_12MB: + return 0xA; + case IEEE80211_OFDM_RATE_18MB: + return 0xE; + case IEEE80211_OFDM_RATE_24MB: + return 0x9; + case IEEE80211_OFDM_RATE_36MB: + return 0xD; + case IEEE80211_OFDM_RATE_48MB: + return 0x8; + case IEEE80211_OFDM_RATE_54MB: + return 0xC; + } + assert(0); + return 0; +} + +static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, + u16 octets, const u8 bitrate, + const int ofdm_modulation) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + /* Account for hardware-appended FCS. */ + octets += IEEE80211_FCS_LEN; + + if (ofdm_modulation) { + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + assert(!(octets & 0xF000)); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == IEEE80211_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); + } + +//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); +} + +void fastcall +bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) +{ + const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; + const struct ieee80211_security *secinfo = &bcm->ieee->sec; + u8 bitrate; + int ofdm_modulation; + u8 fallback_bitrate; + int fallback_ofdm_modulation; + u16 tmp; + u16 encrypt_frame; + + /* Now construct the TX header. */ + memset(txhdr, 0, sizeof(*txhdr)); + + //TODO: Some RTS/CTS stuff has to be done. + //TODO: Encryption stuff. + //TODO: others? + + bitrate = bcm->softmac->txrates.default_rate; + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_bitrate = bcm->softmac->txrates.default_fallback; + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + /* Set Frame Control from 80211 header. */ + txhdr->frame_control = wireless_header->frame_ctl; + /* Copy address1 from 80211 header. */ + memcpy(txhdr->mac1, wireless_header->addr1, 6); + /* Set the fallback duration ID. */ + //FIXME: We use the original durid for now. + txhdr->fallback_dur_id = wireless_header->duration_id; + + /* Set the cookie (used as driver internal ID for the frame) */ + txhdr->cookie = cpu_to_le16(cookie); + + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; + if (encrypt_frame && !bcm->ieee->host_encrypt) { + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; + if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) { + dprintkl(KERN_ERR PFX "invalid packet with PROTECTED" + "flag set discarded"); + return; + } + memcpy(txhdr->wep_iv, hdr->payload, 4); + /* Hardware appends ICV. */ + fragment_len += 4; + } + + /* Generate the PLCP header and the fallback PLCP header. */ + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), + fragment_len, + bitrate, ofdm_modulation); + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len, + fallback_bitrate, fallback_ofdm_modulation); + + /* Set the CONTROL field */ + tmp = 0; + if (ofdm_modulation) + tmp |= BCM43xx_TXHDRCTL_OFDM; + if (bcm->short_preamble) //FIXME: could be the other way around, please test + tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; + tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; + txhdr->control = cpu_to_le16(tmp); + + /* Set the FLAGS field */ + tmp = 0; + if (!is_multicast_ether_addr(wireless_header->addr1) && + !is_broadcast_ether_addr(wireless_header->addr1)) + tmp |= BCM43xx_TXHDRFLAG_EXPECTACK; + if (1 /* FIXME: PS poll?? */) + tmp |= 0x10; // FIXME: unknown meaning. + if (fallback_ofdm_modulation) + tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; + if (is_first_fragment) + tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; + txhdr->flags = cpu_to_le16(tmp); + + /* Set WSEC/RATE field */ + if (encrypt_frame && !bcm->ieee->host_encrypt) { + tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) + & BCM43xx_TXHDR_WSEC_ALGO_MASK; + tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; + txhdr->wsec_rate = cpu_to_le16(tmp); + } + +//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header"); +} + +static +void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, + u16 offset, + const u8 *mac) +{ + u16 data; + + offset |= 0x0020; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); +} + +static inline +void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, + u16 offset) +{ + const u8 zero_addr[ETH_ALEN] = { 0 }; + + bcm43xx_macfilter_set(bcm, offset, zero_addr); +} + +static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); + const u8 *bssid = (const u8 *)(bcm->ieee->bssid); + u8 mac_bssid[ETH_ALEN * 2]; + int i; + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); +} + +static inline +void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) +{ + /* slot_time is in usec. */ + if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) + return; + bcm43xx_write16(bcm, 0x684, 510 + slot_time); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); +} + +static inline +void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 9); +} + +static inline +void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 20); +} + +//FIXME: rename this func? +static void bcm43xx_disassociate(struct bcm43xx_private *bcm) +{ + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + + bcm43xx_ram_write(bcm, 0x0026, 0x0000); + bcm43xx_ram_write(bcm, 0x0028, 0x0000); + bcm43xx_ram_write(bcm, 0x007E, 0x0000); + bcm43xx_ram_write(bcm, 0x0080, 0x0000); + bcm43xx_ram_write(bcm, 0x047E, 0x0000); + bcm43xx_ram_write(bcm, 0x0480, 0x0000); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x060E, 0x0000); + } else + bcm43xx_write32(bcm, 0x0188, 0x80000000); + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) + bcm43xx_short_slot_timing_enable(bcm); + + bcm43xx_mac_enable(bcm); +} + +//FIXME: rename this func? +static void bcm43xx_associate(struct bcm43xx_private *bcm, + const u8 *mac) +{ + memcpy(bcm->ieee->bssid, mac, ETH_ALEN); + + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); + bcm43xx_write_mac_bssid_templates(bcm); + bcm43xx_mac_enable(bcm); +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* Make sure we don't receive more data from the device. */ +static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) +{ + u32 old; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { + spin_unlock_irqrestore(&bcm->lock, flags); + return -EBUSY; + } + old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + tasklet_disable(&bcm->isr_tasklet); + spin_unlock_irqrestore(&bcm->lock, flags); + if (oldstate) + *oldstate = old; + + return 0; +} + +static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) +{ + u32 radio_id; + u16 manufact; + u16 version; + u8 revision; + s8 i; + + if (bcm->chip_id == 0x4317) { + if (bcm->chip_rev == 0x00) + radio_id = 0x3205017F; + else if (bcm->chip_rev == 0x01) + radio_id = 0x4205017F; + else + radio_id = 0x5205017F; + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH); + radio_id <<= 16; + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); + } + + manufact = (radio_id & 0x00000FFF); + version = (radio_id & 0x0FFFF000) >> 12; + revision = (radio_id & 0xF0000000) >> 28; + + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", + radio_id, manufact, version, revision); + + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_B: + if ((version & 0xFFF0) != 0x2050) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_G: + if (version != 0x2050) + goto err_unsupported_radio; + break; + } + + bcm->current_core->radio->manufact = manufact; + bcm->current_core->radio->version = version; + bcm->current_core->radio->revision = revision; + + /* Set default attenuation values. */ + bcm->current_core->radio->txpower[0] = 2; + bcm->current_core->radio->txpower[1] = 2; + if (revision == 1) + bcm->current_core->radio->txpower[2] = 3; + else + bcm->current_core->radio->txpower[2] = 0; + + /* Initialize the in-memory nrssi Lookup Table. */ + for (i = 0; i < 64; i++) + bcm->current_core->radio->nrssi_lt[i] = i; + + return 0; + +err_unsupported_radio: + printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n"); + return -ENODEV; +} + +static const char * bcm43xx_locale_iso(u8 locale) +{ + /* ISO 3166-1 country codes. + * Note that there aren't ISO 3166-1 codes for + * all or locales. (Not all locales are countries) + */ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + case BCM43xx_LOCALE_ALL: + return "XX"; + case BCM43xx_LOCALE_THAILAND: + return "TH"; + case BCM43xx_LOCALE_ISRAEL: + return "IL"; + case BCM43xx_LOCALE_JORDAN: + return "JO"; + case BCM43xx_LOCALE_CHINA: + return "CN"; + case BCM43xx_LOCALE_JAPAN: + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JP"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + case BCM43xx_LOCALE_USA_LOW: + return "US"; + case BCM43xx_LOCALE_EUROPE: + return "EU"; + case BCM43xx_LOCALE_NONE: + return " "; + } + assert(0); + return " "; +} + +static const char * bcm43xx_locale_string(u8 locale) +{ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + return "World"; + case BCM43xx_LOCALE_THAILAND: + return "Thailand"; + case BCM43xx_LOCALE_ISRAEL: + return "Israel"; + case BCM43xx_LOCALE_JORDAN: + return "Jordan"; + case BCM43xx_LOCALE_CHINA: + return "China"; + case BCM43xx_LOCALE_JAPAN: + return "Japan"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + return "USA/Canada/ANZ"; + case BCM43xx_LOCALE_EUROPE: + return "Europe"; + case BCM43xx_LOCALE_USA_LOW: + return "USAlow"; + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JapanHigh"; + case BCM43xx_LOCALE_ALL: + return "All"; + case BCM43xx_LOCALE_NONE: + return "None"; + } + assert(0); + return ""; +} + +static inline u8 bcm43xx_crc8(u8 crc, u8 data) +{ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +u8 bcm43xx_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) { + crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF); + crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + + +static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) +{ + int i; + u16 value; + u16 *sprom; + u8 crc, expected_crc; +#ifdef CONFIG_BCM947XX + char *c; +#endif + + sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), + GFP_KERNEL); + if (!sprom) { + printk(KERN_ERR PFX "read_sprom OOM\n"); + return -ENOMEM; + } +#ifdef CONFIG_BCM947XX + sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2")); + sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags")); + + if ((c = nvram_get("il0macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR])); + + if ((c = nvram_get("et1macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR])); + + sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0")); + sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1")); + sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2")); + + sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0")); + sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1")); + sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2")); + + sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); +#else + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + + /* CRC-8 check. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " + "(0x%02X, expected: 0x%02X)\n", + crc, expected_crc); + } +#endif + + /* boardflags2 */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS2]; + bcm->sprom.boardflags2 = value; + + /* il0macaddr */ + value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; + *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; + *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; + *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); + + /* et0macaddr */ + value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; + *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; + *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; + *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); + + /* et1macaddr */ + value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; + *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; + *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; + *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); + + /* ethernet phy settings */ + value = sprom[BCM43xx_SPROM_ETHPHY]; + bcm->sprom.et0phyaddr = (value & 0x001F); + bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5; + bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14; + bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15; + + /* boardrev, antennas, locale */ + value = sprom[BCM43xx_SPROM_BOARDREV]; + bcm->sprom.boardrev = (value & 0x00FF); + bcm->sprom.locale = (value & 0x0F00) >> 8; + bcm->sprom.antennas_aphy = (value & 0x3000) >> 12; + bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14; + if (modparam_locale != -1) { + if (modparam_locale >= 0 && modparam_locale <= 11) { + bcm->sprom.locale = modparam_locale; + printk(KERN_WARNING PFX "Operating with modified " + "LocaleCode %u (%s)\n", + bcm->sprom.locale, + bcm43xx_locale_string(bcm->sprom.locale)); + } else { + printk(KERN_WARNING PFX "Module parameter \"locale\" " + "invalid value. (0 - 11)\n"); + } + } + + /* pa0b* */ + value = sprom[BCM43xx_SPROM_PA0B0]; + bcm->sprom.pa0b0 = value; + value = sprom[BCM43xx_SPROM_PA0B1]; + bcm->sprom.pa0b1 = value; + value = sprom[BCM43xx_SPROM_PA0B2]; + bcm->sprom.pa0b2 = value; + + /* wl0gpio* */ + value = sprom[BCM43xx_SPROM_WL0GPIO0]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio0 = value & 0x00FF; + bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8; + value = sprom[BCM43xx_SPROM_WL0GPIO2]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio2 = value & 0x00FF; + bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8; + + /* maxpower */ + value = sprom[BCM43xx_SPROM_MAXPWR]; + bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8; + bcm->sprom.maxpower_bgphy = value & 0x00FF; + + /* pa1b* */ + value = sprom[BCM43xx_SPROM_PA1B0]; + bcm->sprom.pa1b0 = value; + value = sprom[BCM43xx_SPROM_PA1B1]; + bcm->sprom.pa1b1 = value; + value = sprom[BCM43xx_SPROM_PA1B2]; + bcm->sprom.pa1b2 = value; + + /* idle tssi target */ + value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT]; + bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF; + bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8; + + /* boardflags */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS]; + if (value == 0xFFFF) + value = 0x0000; + bcm->sprom.boardflags = value; + + /* antenna gain */ + value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; + if (value == 0x0000 || value == 0xFFFF) + value = 0x0202; + /* convert values to Q5.2 */ + bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4; + bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4; + + kfree(sprom); + + return 0; +} + +static int bcm43xx_channel_is_allowed(struct bcm43xx_private *bcm, u8 channel, + u8 *max_power, u8 *flags) +{ + /* THIS FUNCTION DOES _NOT_ ENFORCE REGULATORY DOMAIN COMPLIANCE. + * It is only a helper function to make life easier to + * select legal channels and transmission powers. + */ + + u8 phytype = bcm->current_core->phy->type; + int allowed = 0; + + *max_power = 0; + *flags = 0; + + //FIXME: Set max_power and maybe flags + /*FIXME: Allowed channels are sometimes different for outdoor + * or indoor use. See modparam_outdoor. + */ + /* From b specs Max Power BPHY: + * USA: 1000mW + * Europe: 100mW + * Japan: 10mW/MHz + */ + + switch (bcm->sprom.locale) { + case BCM43xx_LOCALE_WORLD: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_THAILAND: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_ISRAEL: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 5 && channel <= 7) + allowed = 1; + } else { + if (channel >= 5 && channel <= 7) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JORDAN: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 10 && channel <= 13) + allowed = 1; + } else { + if (channel >= 10 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_CHINA: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JAPAN: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + //FIXME: This seems to be wrong. + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + //FIXME: This seems to be wrong. + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 11) + allowed = 1; + } + break; + case BCM43xx_LOCALE_EUROPE: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_USA_LOW: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 11) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JAPAN_HIGH: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + //FIXME? + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_ALL: + allowed = 1; + break; + case BCM43xx_LOCALE_NONE: + break; + default: + assert(0); + } + + return allowed; +} + +static void bcm43xx_geo_init(struct bcm43xx_private *bcm) +{ + struct ieee80211_geo geo; + struct ieee80211_channel *chan; + int have_a = 0, have_bg = 0; + int i, num80211; + u8 channel, flags, max_power; + struct bcm43xx_phyinfo *phy; + const char *iso_country; + + memset(&geo, 0, sizeof(geo)); + num80211 = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < num80211; i++) { + phy = bcm->phy + i; + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + have_bg = 1; + break; + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + default: + assert(0); + } + } + iso_country = bcm43xx_locale_iso(bcm->sprom.locale); + + if (have_a) { + for (i = 0, channel = 0; channel < 201; channel++) { + if (!bcm43xx_channel_is_allowed(bcm, channel, + &max_power, &flags)) + continue; + chan = &geo.a[i++]; + chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->channel = channel; + chan->flags = flags; + chan->max_power = max_power; + } + geo.a_channels = i; + } + if (have_bg) { + for (i = 0, channel = 1; channel < 15; channel++) { + if (!bcm43xx_channel_is_allowed(bcm, channel, + &max_power, &flags)) + continue; + chan = &geo.bg[i++]; + chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->channel = channel; + chan->flags = flags; + chan->max_power = max_power; + } + geo.bg_channels = i; + } + memcpy(geo.name, iso_country, 2); + if (0 /*TODO: Outdoor use only */) + geo.name[2] = 'O'; + else if (0 /*TODO: Indoor use only */) + geo.name[2] = 'I'; + else + geo.name[2] = ' '; + geo.name[3] = '\0'; + + ieee80211_set_geo(bcm->ieee, &geo); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) +{ + unsigned int i, max_loop; + u16 value = 0; + u32 buffer[5] = { + 0x00000000, + 0x0000D400, + 0x00000000, + 0x00000001, + 0x00000000, + }; + + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + max_loop = 0x1E; + buffer[0] = 0xCC010200; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x6E840B00; + break; + default: + assert(0); + return; + } + + for (i = 0; i < 5; i++) + bcm43xx_ram_write(bcm, i * 4, buffer[i]); + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + + bcm43xx_write16(bcm, 0x0568, 0x0000); + bcm43xx_write16(bcm, 0x07C0, 0x0000); + bcm43xx_write16(bcm, 0x050C, ((bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); + bcm43xx_write16(bcm, 0x0508, 0x0000); + bcm43xx_write16(bcm, 0x050A, 0x0000); + bcm43xx_write16(bcm, 0x054C, 0x0000); + bcm43xx_write16(bcm, 0x056A, 0x0014); + bcm43xx_write16(bcm, 0x0568, 0x0826); + bcm43xx_write16(bcm, 0x0500, 0x0000); + bcm43xx_write16(bcm, 0x0502, 0x0030); + + for (i = 0x00; i < max_loop; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if ((value & 0x0080) != 0) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if ((value & 0x0400) != 0) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x0690); + if ((value & 0x0100) == 0) + break; + udelay(10); + } +} + +static void key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, const u16 *key) +{ + unsigned int i, basic_wep = 0; + u32 offset; + u16 value; + + /* Write associated key information */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), + ((index << 4) | (algorithm & 0x0F))); + + /* The first 4 WEP keys need extra love */ + if (((algorithm == BCM43xx_SEC_ALGO_WEP) || + (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) + basic_wep = 1; + + /* Write key payload, 8 little endian words */ + offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); + for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { + value = cpu_to_le16(key[i]); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2), value); + + if (!basic_wep) + continue; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, + value); + } +} + +static void keymac_write(struct bcm43xx_private *bcm, + u8 index, const u32 *addr) +{ + /* for keys 0-3 there is no associated mac address */ + if (index < 4) + return; + + index -= 4; + if (bcm->current_core->rev >= 5) { + bcm43xx_shm_write32(bcm, + BCM43xx_SHM_HWMAC, + index * 2, + cpu_to_be32(*addr)); + bcm43xx_shm_write16(bcm, + BCM43xx_SHM_HWMAC, + (index * 2) + 1, + cpu_to_be16(*((u16 *)(addr + 1)))); + } else { + if (index < 8) { + TODO(); /* Put them in the macaddress filter */ + } else { + TODO(); + /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. + Keep in mind to update the count of keymacs in 0x003E as well! */ + } + } +} + +static int bcm43xx_key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, + const u8 *_key, int key_len, + const u8 *mac_addr) +{ + u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; + + if (index >= ARRAY_SIZE(bcm->key)) + return -EINVAL; + if (key_len > ARRAY_SIZE(key)) + return -EINVAL; + if (algorithm < 1 || algorithm > 5) + return -EINVAL; + + memcpy(key, _key, key_len); + key_write(bcm, index, algorithm, (const u16 *)key); + keymac_write(bcm, index, (const u32 *)mac_addr); + + bcm->key[index].algorithm = algorithm; + + return 0; +} + +static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) +{ + static const u32 zero_mac[2] = { 0 }; + unsigned int i,j, nr_keys = 54; + u16 offset; + + if (bcm->current_core->rev < 5) + nr_keys = 16; + assert(nr_keys <= ARRAY_SIZE(bcm->key)); + + for (i = 0; i < nr_keys; i++) { + bcm->key[i].enabled = 0; + /* returns for i < 4 immediately */ + keymac_write(bcm, i, zero_mac); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + 0x100 + (i * 2), 0x0000); + for (j = 0; j < 8; j++) { + offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset, 0x0000); + } + } + dprintk(KERN_INFO PFX "Keys cleared\n"); +} + +/* Puts the index of the current core into user supplied core variable. + * This function reads the value from the device. + * Almost always you don't want to call this, but use bcm->current_core + */ +static inline +int _get_current_core(struct bcm43xx_private *bcm, int *core) +{ + int err; + + err = bcm43xx_pci_read_config32(bcm, BCM43xx_REG_ACTIVE_CORE, core); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE read failed!\n"); + return -ENODEV; + } + *core = (*core - 0x18000000) / 0x1000; + + return 0; +} + +/* Lowlevel core-switch function. This is only to be used in + * bcm43xx_switch_core() and bcm43xx_probe_cores() + */ +static int _switch_core(struct bcm43xx_private *bcm, int core) +{ + int err; + int attempts = 0; + int current_core = -1; + + assert(core >= 0); + + err = _get_current_core(bcm, ¤t_core); + if (unlikely(err)) + goto out; + + /* Write the computed value to the register. This doesn't always + succeed so we retry BCM43xx_SWITCH_CORE_MAX_RETRIES times */ + while (current_core != core) { + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) { + err = -ENODEV; + printk(KERN_ERR PFX + "unable to switch to core %u, retried %i times\n", + core, attempts); + goto out; + } + err = bcm43xx_pci_write_config32(bcm, BCM43xx_REG_ACTIVE_CORE, + (core * 0x1000) + 0x18000000); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE write failed!\n"); + continue; + } + _get_current_core(bcm, ¤t_core); +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + bcm->current_core_offset = 0x1000 * core; + else + bcm->current_core_offset = 0; +#endif + } + + assert(err == 0); +out: + return err; +} + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) +{ + int err; + + if (!new_core) + return 0; + + if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) + return -ENODEV; + if (bcm->current_core == new_core) + return 0; + err = _switch_core(bcm, new_core->index); + if (!err) + bcm->current_core = new_core; + + return err; +} + +static inline int bcm43xx_core_enabled(struct bcm43xx_private *bcm) +{ + u32 value; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET + | BCM43xx_SBTMSTATELOW_REJECT; + + return (value == BCM43xx_SBTMSTATELOW_CLOCK); +} + +/* disable current core */ +static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + int i; + + /* fetch sbtmstatelow from core information registers */ + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + + /* core is already in reset */ + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) + goto out; + + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + + for (i = 0; i < 1000; i++) { + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); + return -EBUSY; + } + + for (i = 0; i < 1000; i++) { + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); + return -EBUSY; + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(10); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_REJECT | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + +out: + bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED; + return 0; +} + +/* enable (reset) current core */ +static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + u32 sbimstate; + int err; + + err = bcm43xx_core_disable(bcm, core_flags); + if (err) + goto out; + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { + sbtmstatehigh = 0x00000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); + } + + sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); + if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { + sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED; + assert(err == 0); +out: + return err; +} + +/* http://bcm-specs.sipsolutions.net/80211CoreReset */ +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) +{ + u32 flags = 0x00040000; + + if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) { +//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? +#ifndef CONFIG_BCM947XX + /* reset all used DMA controllers. */ + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + if (bcm->current_core->rev < 5) + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); +#endif + } + if (bcm->shutting_down) { + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); + } else { + if (connect_phy) + flags |= 0x20000000; + bcm43xx_phy_connect(bcm, connect_phy); + bcm43xx_core_enable(bcm, flags); + bcm43xx_write16(bcm, 0x03E6, 0x0000); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_400); + } +} + +static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + bcm43xx_write16(bcm, 0x03E6, 0x00F4); + bcm43xx_core_disable(bcm, 0); +} + +/* Mark the current 80211 core inactive. + * "active_80211_core" is the other 80211 core, which is used. + */ +static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, + struct bcm43xx_coreinfo *active_80211_core) +{ + u32 sbtmstatelow; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x200a0000; + sbtmstatelow |= 0xa0000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0xa0000; + sbtmstatelow |= 0x80000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, active_80211_core); + if (err) + goto out; + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x20000000; + sbtmstatelow |= 0x20000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + err = bcm43xx_switch_core(bcm, old_core); + } + +out: + return err; +} + +static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) +{ + u32 v0, v1; + u16 tmp; + struct bcm43xx_xmitstatus stat; + + assert(bcm->current_core->id == BCM43xx_COREID_80211); + assert(bcm->current_core->rev >= 5); + + while (1) { + v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); + if (!v0) + break; + v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16) & 0x0000FFFF; + tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); + stat.flags = tmp & 0xFF; + stat.cnt1 = (tmp & 0x0F00) >> 8; + stat.cnt2 = (tmp & 0xF000) >> 12; + stat.seq = (u16)(v1 & 0xFFFF); + stat.unknown = (u16)((v1 >> 16) & 0xFF); + + bcm43xx_debugfs_log_txstat(bcm, &stat); + + if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE) + continue; + if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) { + //TODO: packet was not acked (was lost) + } + //TODO: There are more (unknown) flags to test. see bcm43xx_main.h + + if (bcm->pio_mode) + bcm43xx_pio_handle_xmitstatus(bcm, &stat); + else + bcm43xx_dma_handle_xmitstatus(bcm, &stat); + } +} + +static inline void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) +{ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); + assert(bcm->noisecalc.core_at_start == bcm->current_core); + assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel); +} + +static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) +{ + /* Top half of Link Quality calculation. */ + + if (bcm->noisecalc.calculation_running) + return; + bcm->noisecalc.core_at_start = bcm->current_core; + bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel; + bcm->noisecalc.calculation_running = 1; + bcm->noisecalc.nr_samples = 0; + + bcm43xx_generate_noise_sample(bcm); +} + +static inline void handle_irq_noise(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 tmp; + u8 noise[4]; + u8 i, j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + assert(bcm->noisecalc.calculation_running); + if (bcm->noisecalc.core_at_start != bcm->current_core || + bcm->noisecalc.channel_at_start != radio->channel) + goto drop_calculation; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); + noise[0] = (tmp & 0x00FF); + noise[1] = (tmp & 0xFF00) >> 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); + noise[2] = (tmp & 0x00FF); + noise[3] = (tmp & 0xFF00) >> 8; + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + assert(bcm->noisecalc.nr_samples <= 8); + i = bcm->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; + bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; + bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; + bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; + bcm->noisecalc.nr_samples++; + if (bcm->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += bcm->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + if (average > -65) + bcm->stats.link_quality = 0; + else if (average > -75) + bcm->stats.link_quality = 1; + else if (average > -85) + bcm->stats.link_quality = 2; + else + bcm->stats.link_quality = 3; +// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average); +drop_calculation: + bcm->noisecalc.calculation_running = 0; + return; + } +generate_new: + bcm43xx_generate_noise_sample(bcm); +} + +static inline +void handle_irq_ps(struct bcm43xx_private *bcm) +{ + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + ///TODO: PS TBTT + } else { + if (1/*FIXME: the last PSpoll frame was sent successfully */) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + if (bcm->ieee->iw_mode == IW_MODE_ADHOC) + bcm->reg124_set_0x4 = 1; + //FIXME else set to false? +} + +static inline +void handle_irq_reg124(struct bcm43xx_private *bcm) +{ + if (!bcm->reg124_set_0x4) + return; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) + | 0x4); + //FIXME: reset reg124_set_0x4 to false? +} + +static inline +void handle_irq_pmq(struct bcm43xx_private *bcm) +{ + u32 tmp; + + //TODO: AP mode. + + while (1) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002); +} + +static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, + u16 ram_offset, u16 shm_size_offset) +{ + u32 value; + u16 size = 0; + + /* Timestamp. */ + //FIXME: assumption: The chip sets the timestamp + value = 0; + bcm43xx_ram_write(bcm, ram_offset++, value); + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 8; + + /* Beacon Interval / Capability Information */ + value = 0x0000;//FIXME: Which interval? + value |= (1 << 0) << 16; /* ESS */ + value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? + value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? + if (!bcm->ieee->open_wep) + value |= (1 << 4) << 16; /* Privacy */ + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 4; + + /* SSID */ + //TODO + + /* FH Parameter Set */ + //TODO + + /* DS Parameter Set */ + //TODO + + /* CF Parameter Set */ + //TODO + + /* TIM */ + //TODO + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); +} + +static inline +void handle_irq_beacon(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); + + if ((status & 0x1) && (status & 0x2)) { + /* ACK beacon IRQ. */ + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, + BCM43xx_IRQ_BEACON); + bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; + return; + } + if (!(status & 0x1)) { + bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); + status |= 0x1; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } + if (!(status & 0x2)) { + bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); + status |= 0x2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } +} + +/* Debug helper for irq bottom-half to print all reason registers. */ +#define bcmirq_print_reasons(description) \ + do { \ + dprintkl(KERN_ERR PFX description "\n" \ + KERN_ERR PFX " Generic Reason: 0x%08x\n" \ + KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \ + KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \ + reason, \ + dma_reason[0], dma_reason[1], \ + dma_reason[2], dma_reason[3], \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \ + } while (0) + +/* Interrupt handler bottom-half */ +static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) +{ + u32 reason; + u32 dma_reason[4]; + int activity = 0; + unsigned long flags; + +#ifdef CONFIG_BCM43XX_DEBUG + u32 _handled = 0x00000000; +# define bcmirq_handled(irq) do { _handled |= (irq); } while (0) +#else +# define bcmirq_handled(irq) do { /* nothing */ } while (0) +#endif /* CONFIG_BCM43XX_DEBUG*/ + + spin_lock_irqsave(&bcm->lock, flags); + reason = bcm->irq_reason; + dma_reason[0] = bcm->dma_reason[0]; + dma_reason[1] = bcm->dma_reason[1]; + dma_reason[2] = bcm->dma_reason[2]; + dma_reason[3] = bcm->dma_reason[3]; + + if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { + /* TX error. We get this when Template Ram is written in wrong endianess + * in dummy_tx(). We also get this if something is wrong with the TX header + * on DMA or PIO queues. + * Maybe we get this in other error conditions, too. + */ + bcmirq_print_reasons("XMIT ERROR"); + bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); + } + + if (reason & BCM43xx_IRQ_PS) { + handle_irq_ps(bcm); + bcmirq_handled(BCM43xx_IRQ_PS); + } + + if (reason & BCM43xx_IRQ_REG124) { + handle_irq_reg124(bcm); + bcmirq_handled(BCM43xx_IRQ_REG124); + } + + if (reason & BCM43xx_IRQ_BEACON) { + if (bcm->ieee->iw_mode == IW_MODE_MASTER) + handle_irq_beacon(bcm); + bcmirq_handled(BCM43xx_IRQ_BEACON); + } + + if (reason & BCM43xx_IRQ_PMQ) { + handle_irq_pmq(bcm); + bcmirq_handled(BCM43xx_IRQ_PMQ); + } + + if (reason & BCM43xx_IRQ_SCAN) { + /*TODO*/ + //bcmirq_handled(BCM43xx_IRQ_SCAN); + } + + if (reason & BCM43xx_IRQ_NOISE) { + handle_irq_noise(bcm); + bcmirq_handled(BCM43xx_IRQ_NOISE); + } + + /* Check the DMA reason registers for received data. */ + assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); + assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); + if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { + if (bcm->pio_mode) + bcm43xx_pio_rx(bcm->current_core->pio->queue0); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); + activity = 1; + } + if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { + if (likely(bcm->current_core->rev < 5)) { + if (bcm->pio_mode) + bcm43xx_pio_rx(bcm->current_core->pio->queue3); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + activity = 1; + } else + assert(0); + } + bcmirq_handled(BCM43xx_IRQ_RX); + + if (reason & BCM43xx_IRQ_XMIT_STATUS) { + if (bcm->current_core->rev >= 5) { + handle_irq_transmit_status(bcm); + activity = 1; + } + //TODO: In AP mode, this also causes sending of powersave responses. + bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); + } + + /* We get spurious IRQs, althought they are masked. + * Assume they are void and ignore them. + */ + bcmirq_handled(~(bcm->irq_savedstate)); + /* IRQ_PIO_WORKAROUND is handled in the top-half. */ + bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); +#ifdef CONFIG_BCM43XX_DEBUG + if (unlikely(reason & ~_handled)) { + printkl(KERN_WARNING PFX + "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " + "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + reason, (reason & ~_handled), + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } +#endif +#undef bcmirq_handled + + if (!modparam_noleds) + bcm43xx_leds_update(bcm, activity); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + spin_unlock_irqrestore(&bcm->lock, flags); +} + +#undef bcmirq_print_reasons + +static inline +void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, + u32 reason, u32 mask) +{ + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) + & 0x0001dc00; + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) + & 0x0000dc00; + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) + & 0x0000dc00; + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) + & 0x0001dc00; + + if ((bcm->pio_mode) && + (bcm->current_core->rev < 3) && + (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + +#define apply_pio_workaround(BASE, QNUM) \ + do { \ + if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \ + bcm->dma_reason[QNUM] |= 0x00010000; \ + else \ + bcm->dma_reason[QNUM] &= ~0x00010000; \ + } while (0) + + apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0); + apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1); + apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2); + apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3); + +#undef apply_pio_workaround + } + + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, + reason & mask); + + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, + bcm->dma_reason[0]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, + bcm->dma_reason[1]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, + bcm->dma_reason[2]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, + bcm->dma_reason[3]); +} + +/* Interrupt handler top-half */ +static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bcm43xx_private *bcm = dev_id; + u32 reason, mask; + + if (!bcm) + return IRQ_NONE; + + spin_lock(&bcm->lock); + + reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) { + /* irq not for us (shared irq) */ + spin_unlock(&bcm->lock); + return IRQ_NONE; + } + mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + if (!(reason & mask)) { + spin_unlock(&bcm->lock); + return IRQ_HANDLED; + } + + bcm43xx_interrupt_ack(bcm, reason, mask); + + /* disable all IRQs. They are enabled again in the bottom half. */ + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + + /* save the reason code and call our bottom half. */ + bcm->irq_reason = reason; + tasklet_schedule(&bcm->isr_tasklet); + + spin_unlock(&bcm->lock); + + return IRQ_HANDLED; +} + +static void bcm43xx_release_firmware(struct bcm43xx_private *bcm) +{ + if (bcm->firmware_norelease) + return; /* Suspending or controller reset. */ + release_firmware(bcm->ucode); + bcm->ucode = NULL; + release_firmware(bcm->pcm); + bcm->pcm = NULL; + release_firmware(bcm->initvals0); + bcm->initvals0 = NULL; + release_firmware(bcm->initvals1); + bcm->initvals1 = NULL; +} + +static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u8 rev = bcm->current_core->rev; + int err = 0; + int nr; + char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; + + if (!bcm->ucode) { + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", + (rev >= 5 ? 5 : rev), + modparam_fwpostfix); + err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: Microcode \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->pcm) { + snprintf(buf, ARRAY_SIZE(buf), + "bcm43xx_pcm%d%s.fw", + (rev < 5 ? 4 : 5), + modparam_fwpostfix); + err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: PCM \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->initvals0) { + if (rev == 2 || rev == 4) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 3; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 1; + break; + default: + goto err_noinitval; + } + + } else if (rev >= 5) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 7; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 5; + break; + default: + goto err_noinitval; + } + } else + goto err_noinitval; + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + + if (!bcm->initvals1) { + if (rev >= 5) { + u32 sbtmstatehigh; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & 0x00010000) + nr = 9; + else + nr = 10; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 6; + break; + default: + goto err_noinitval; + } + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + } + +out: + return err; +error: + bcm43xx_release_firmware(bcm); + goto out; +err_noinitval: + printk(KERN_ERR PFX "Error: No InitVals available!\n"); + err = -ENOENT; + goto error; +} + +static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) +{ + const u32 *data; + unsigned int i, len; + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_enable(bcm); +#else + bcm43xx_mmioprint_disable(bcm); +#endif + + /* Upload Microcode. */ + data = (u32 *)(bcm->ucode->data); + len = bcm->ucode->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + + /* Upload PCM data. */ + data = (u32 *)(bcm->pcm->data); + len = bcm->pcm->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_disable(bcm); +#else + bcm43xx_mmioprint_enable(bcm); +#endif +} + +static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, + const struct bcm43xx_initval *data, + const unsigned int len) +{ + u16 offset, size; + u32 value; + unsigned int i; + + for (i = 0; i < len; i++) { + offset = be16_to_cpu(data[i].offset); + size = be16_to_cpu(data[i].size); + value = be32_to_cpu(data[i].value); + + if (size == 2) + bcm43xx_write16(bcm, offset, value); + else if (size == 4) + bcm43xx_write32(bcm, offset, value); + else + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + } +} + +static void bcm43xx_upload_initvals(struct bcm43xx_private *bcm) +{ +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_enable(bcm); +#else + bcm43xx_mmioprint_disable(bcm); +#endif + + bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + if (bcm->initvals1) { + bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + } + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_disable(bcm); +#else + bcm43xx_mmioprint_enable(bcm); +#endif +} + +static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) +{ + int res; + unsigned int i; + u32 data; + + bcm->irq = bcm->pci_dev->irq; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) { + struct pci_dev *d = NULL; + /* FIXME: we will probably need more device IDs here... */ + d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); + if (d != NULL) { + bcm->irq = d->irq; + } + } +#endif + res = request_irq(bcm->irq, bcm43xx_interrupt_handler, + SA_SHIRQ, DRV_NAME, bcm); + if (res) { + printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); + return -EFAULT; + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); + i = 0; + while (1) { + data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (data == BCM43xx_IRQ_READY) + break; + i++; + if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { + printk(KERN_ERR PFX "Card IRQ register not responding. " + "Giving up.\n"); + free_irq(bcm->irq, bcm); + return -ENODEV; + } + udelay(10); + } + // dummy read + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + + return 0; +} + +/* Switch to the core used to write the GPIO register. + * This is either the ChipCommon, or the PCI core. + */ +static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) +{ + int err; + + /* Where to find the GPIO register depends on the chipset. + * If it has a ChipCommon, its register at offset 0x6c is the GPIO + * control register. Otherwise the register at offset 0x6c in the + * PCI core is the GPIO control register. + */ + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) { + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err == -ENODEV) { + printk(KERN_ERR PFX "gpio error: " + "Neither ChipCommon nor PCI core available!\n"); + return -ENODEV; + } else if (err != 0) + return -ENODEV; + } else if (err != 0) + return -ENODEV; + + return 0; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + u32 mask, value; + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value &= ~0xc000; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + + mask = 0x0000001F; + value = 0x0000000F; + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); + + old_core = bcm->current_core; + + err = switch_to_gpio_core(bcm); + if (err) + return err; + + if (bcm->current_core->rev >= 2){ + mask |= 0x10; + value |= 0x10; + } + if (bcm->chip_id == 0x4301) { + mask |= 0x60; + value |= 0x60; + } + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + mask |= 0x200; + value |= 0x200; + } + + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value); + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + return err; + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void bcm43xx_mac_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_MAC_ENABLED); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) +{ + int i; + u32 tmp; + + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~BCM43xx_SBF_MAC_ENABLED); + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + for (i = 1000; i > 0; i--) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (tmp & BCM43xx_IRQ_READY) { + i = -1; + break; + } + udelay(10); + } + if (!i) + printkl(KERN_ERR PFX "Failed to suspend mac!\n"); +} + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&bcm->ieee->lock, flags); + bcm->ieee->iw_mode = iw_mode; + spin_unlock_irqrestore(&bcm->ieee->lock, flags); + if (iw_mode == IW_MODE_MONITOR) + bcm->net_dev->type = ARPHRD_IEEE80211; + else + bcm->net_dev->type = ARPHRD_ETHER; + + if (!bcm->initialized) + return; + + bcm43xx_mac_suspend(bcm); + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + /* Reset status to infrastructured mode */ + status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); + /*FIXME: We actually set promiscuous mode as well, until we don't + * get the HW mac filter working */ + status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC; + + switch (iw_mode) { + case IW_MODE_MONITOR: + status |= (BCM43xx_SBF_MODE_PROMISC | + BCM43xx_SBF_MODE_MONITOR); + break; + case IW_MODE_ADHOC: + status &= ~BCM43xx_SBF_MODE_NOTADHOC; + break; + case IW_MODE_MASTER: + case IW_MODE_SECOND: + case IW_MODE_REPEAT: + /* TODO: No AP/Repeater mode for now :-/ */ + TODO(); + break; + case IW_MODE_INFRA: + /* nothing to be done here... */ + break; + default: + printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode); + } + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + bcm43xx_mac_enable(bcm); +} + +/* This is the opposite of bcm43xx_chip_init() */ +static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + if (!modparam_noleds) + bcm43xx_leds_exit(bcm); + bcm43xx_gpio_cleanup(bcm); + free_irq(bcm->irq, bcm); + bcm43xx_release_firmware(bcm); +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int bcm43xx_chip_init(struct bcm43xx_private *bcm) +{ + int err; + int iw_mode = bcm->ieee->iw_mode; + int tmp; + u32 value32; + u16 value16; + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + BCM43xx_SBF_CORE_READY + | BCM43xx_SBF_400); + + err = bcm43xx_request_firmware(bcm); + if (err) + goto out; + bcm43xx_upload_microcode(bcm); + + err = bcm43xx_initialize_irq(bcm); + if (err) + goto out; + + err = bcm43xx_gpio_init(bcm); + if (err) + goto err_free_irq; + + bcm43xx_upload_initvals(bcm); + bcm43xx_radio_turn_on(bcm); + + if (modparam_noleds) + bcm43xx_leds_turn_off(bcm); + else + bcm43xx_leds_update(bcm, 0); + + bcm43xx_write16(bcm, 0x03E6, 0x0000); + err = bcm43xx_phy_init(bcm); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = bcm->current_core->radio->interfmode; + bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + bcm43xx_radio_set_interference_mitigation(bcm, tmp); + + bcm43xx_phy_set_antenna_diversity(bcm); + bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + value16 = bcm43xx_read16(bcm, 0x005E); + value16 |= 0x0004; + bcm43xx_write16(bcm, 0x005E, value16); + } + bcm43xx_write32(bcm, 0x0100, 0x01000000); + if (bcm->current_core->rev < 5) + bcm43xx_write32(bcm, 0x010C, 0x01000000); + + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + /*FIXME: For now, use promiscuous mode at all times; otherwise we don't + get broadcast or multicast packets */ + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_PROMISC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + if (iw_mode == IW_MODE_MONITOR) { + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_PROMISC; + value32 |= BCM43xx_SBF_MODE_MONITOR; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + } + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= 0x100000; //FIXME: What's this? Is this correct? + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + if (bcm->pio_mode) { + bcm43xx_write32(bcm, 0x0210, 0x00000100); + bcm43xx_write32(bcm, 0x0230, 0x00000100); + bcm43xx_write32(bcm, 0x0250, 0x00000100); + bcm43xx_write32(bcm, 0x0270, 0x00000100); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); + + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3)) + bcm43xx_write16(bcm, 0x0612, 0x0064); + else + bcm43xx_write16(bcm, 0x0612, 0x0032); + } else + bcm43xx_write16(bcm, 0x0612, 0x0002); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x060E, 0x0000); + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x0604, 0x0000); + bcm43xx_write16(bcm, 0x0606, 0x0200); + } else { + bcm43xx_write32(bcm, 0x0188, 0x80000000); + bcm43xx_write32(bcm, 0x018C, 0x02000000); + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00); + + value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value32 |= 0x00100000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32); + + bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm)); + + assert(err == 0); + dprintk(KERN_INFO PFX "Chip initialized\n"); +out: + return err; + +err_radio_off: + bcm43xx_radio_turn_off(bcm); + bcm43xx_gpio_cleanup(bcm); +err_free_irq: + free_irq(bcm->irq, bcm); + goto out; +} + +/* Validate chip access + * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ +static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) +{ + int err = -ENODEV; + u32 value; + u32 shm_backup; + + shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) { + printk(KERN_ERR PFX "Error: SHM mismatch (1) validating chip\n"); + goto out; + } + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) { + printk(KERN_ERR PFX "Error: SHM mismatch (2) validating chip\n"); + goto out; + } + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if ((value | 0x80000000) != 0x80000400) { + printk(KERN_ERR PFX "Error: Bad Status Bitfield while validating chip\n"); + goto out; + } + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (value != 0x00000000) { + printk(KERN_ERR PFX "Error: Bad interrupt reason code while validating chip\n"); + goto out; + } + + err = 0; +out: + return err; +} + +static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) +{ + int err, i; + int current_core; + u32 core_vendor, core_id, core_rev; + u32 sb_id_hi, chip_id_32 = 0; + u16 pci_device, chip_id_16; + u8 core_count; + + memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) + * BCM43xx_MAX_80211_CORES); + + memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo) + * BCM43xx_MAX_80211_CORES); + memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo) + * BCM43xx_MAX_80211_CORES); + + /* map core 0 */ + err = _switch_core(bcm, 0); + if (err) + goto out; + + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + /* if present, chipcommon is always core 0; read the chipid from it */ + if (core_id == BCM43xx_COREID_CHIPCOMMON) { + chip_id_32 = bcm43xx_read32(bcm, 0); + chip_id_16 = chip_id_32 & 0xFFFF; + bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE; + bcm->core_chipcommon.id = core_id; + bcm->core_chipcommon.rev = core_rev; + bcm->core_chipcommon.index = 0; + /* While we are at it, also read the capabilities. */ + bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES); + } else { + /* without a chipCommon, use a hard coded table. */ + pci_device = bcm->pci_dev->device; + if (pci_device == 0x4301) + chip_id_16 = 0x4301; + else if ((pci_device >= 0x4305) && (pci_device <= 0x4307)) + chip_id_16 = 0x4307; + else if ((pci_device >= 0x4402) && (pci_device <= 0x4403)) + chip_id_16 = 0x4402; + else if ((pci_device >= 0x4610) && (pci_device <= 0x4615)) + chip_id_16 = 0x4610; + else if ((pci_device >= 0x4710) && (pci_device <= 0x4715)) + chip_id_16 = 0x4710; +#ifdef CONFIG_BCM947XX + else if ((pci_device >= 0x4320) && (pci_device <= 0x4325)) + chip_id_16 = 0x4309; +#endif + else { + printk(KERN_ERR PFX "Could not determine Chip ID\n"); + return -ENODEV; + } + } + + /* ChipCommon with Core Rev >=4 encodes number of cores, + * otherwise consult hardcoded table */ + if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) { + core_count = (chip_id_32 & 0x0F000000) >> 24; + } else { + switch (chip_id_16) { + case 0x4610: + case 0x4704: + case 0x4710: + core_count = 9; + break; + case 0x4310: + core_count = 8; + break; + case 0x5365: + core_count = 7; + break; + case 0x4306: + core_count = 6; + break; + case 0x4301: + case 0x4307: + core_count = 5; + break; + case 0x4402: + core_count = 3; + break; + default: + /* SOL if we get here */ + assert(0); + core_count = 1; + } + } + + bcm->chip_id = chip_id_16; + bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16; + + dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", + bcm->chip_id, bcm->chip_rev); + dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); + if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) { + dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); + } + + if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) + current_core = 1; + else + current_core = 0; + for ( ; current_core < core_count; current_core++) { + struct bcm43xx_coreinfo *core; + + err = _switch_core(bcm, current_core); + if (err) + goto out; + /* Gather information */ + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + /* extract core_id, core_rev, core_vendor */ + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + current_core, core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" ); + + core = NULL; + switch (core_id) { + case BCM43xx_COREID_PCI: + core = &bcm->core_pci; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_V90: + core = &bcm->core_v90; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple V90 cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_PCMCIA: + core = &bcm->core_pcmcia; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_ETHERNET: + core = &bcm->core_ethernet; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_80211: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + core = &(bcm->core_80211[i]); + if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE)) + break; + core = NULL; + } + if (!core) { + printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n", + BCM43xx_MAX_80211_CORES); + continue; + } + if (i != 0) { + /* More than one 80211 core is only supported + * by special chips. + * There are chips with two 80211 cores, but with + * dangling pins on the second core. Be careful + * and ignore these cores here. + */ + if (bcm->pci_dev->device != 0x4324) { + dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n"); + continue; + } + } + switch (core_rev) { + case 2: + case 4: + case 5: + case 6: + case 7: + case 9: + break; + default: + printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", + core_rev); + err = -ENODEV; + goto out; + } + core->phy = &bcm->phy[i]; + core->phy->antenna_diversity = 0xffff; + core->phy->savedpctlreg = 0xFFFF; + core->phy->minlowsig[0] = 0xFFFF; + core->phy->minlowsig[1] = 0xFFFF; + core->phy->minlowsigpos[0] = 0; + core->phy->minlowsigpos[1] = 0; + spin_lock_init(&core->phy->lock); + core->radio = &bcm->radio[i]; + core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + core->radio->channel = 0xFF; + core->radio->initial_channel = 0xFF; + core->radio->lofcal = 0xFFFF; + core->radio->initval = 0xFFFF; + core->radio->nrssi[0] = -1000; + core->radio->nrssi[1] = -1000; + core->dma = &bcm->dma[i]; + core->pio = &bcm->pio[i]; + break; + case BCM43xx_COREID_CHIPCOMMON: + printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); + break; + default: + printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id); + } + if (core) { + core->flags |= BCM43xx_COREFLAG_AVAILABLE; + core->id = core_id; + core->rev = core_rev; + core->index = current_core; + } + } + + if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) { + printk(KERN_ERR PFX "Error: No 80211 core found!\n"); + err = -ENODEV; + goto out; + } + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + + assert(err == 0); +out: + return err; +} + +static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); + u8 *bssid = bcm->ieee->bssid; + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + random_ether_addr(bssid); + break; + case IW_MODE_MASTER: + case IW_MODE_INFRA: + case IW_MODE_REPEAT: + case IW_MODE_SECOND: + case IW_MODE_MONITOR: + memcpy(bssid, mac, ETH_ALEN); + break; + default: + assert(0); + } +} + +static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, + u16 rate, + int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } + else { + offset = 0x4C0; + offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20, + bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset)); +} + +static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) +{ + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1); + case BCM43xx_PHYTYPE_B: + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0); + break; + default: + assert(0); + } +} + +static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_chip_cleanup(bcm); + bcm43xx_pio_free(bcm); + bcm43xx_dma_free(bcm); + + bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED; +} + +/* http://bcm-specs.sipsolutions.net/80211Init */ +static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) +{ + u32 ucodeflags; + int err; + u32 sbimconfiglow; + u8 limit; + + if (bcm->chip_rev < 5) { + sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) + sbimconfiglow |= 0x32; + else if (bcm->bustype == BCM43xx_BUSTYPE_SB) + sbimconfiglow |= 0x53; + else + assert(0); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); + } + + bcm43xx_phy_calibrate(bcm); + err = bcm43xx_chip_init(bcm); + if (err) + goto out; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev); + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET); + + if (0 /*FIXME: which condition has to be used here? */) + ucodeflags |= 0x00000010; + + /* HW decryption needs to be set now */ + ucodeflags |= 0x40000000; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if (bcm->current_core->phy->rev == 1) + ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; + } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if ((bcm->current_core->phy->rev >= 2) && + (bcm->current_core->radio->version == 0x2050)) + ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; + } + + if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET)) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, ucodeflags); + } + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + limit = limit_value(modparam_short_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit); + limit = limit_value(modparam_long_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit); + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2); + + bcm43xx_rate_memory_init(bcm); + + /* Minimum Contention Window */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); + else + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); + /* Maximum Contention Window */ + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + bcm43xx_gen_bssid(bcm); + bcm43xx_write_mac_bssid_templates(bcm); + + if (bcm->current_core->rev >= 5) + bcm43xx_write16(bcm, 0x043C, 0x000C); + + if (!bcm->pio_mode) { + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; + } else { + err = bcm43xx_pio_init(bcm); + if (err) + goto err_chip_cleanup; + } + bcm43xx_write16(bcm, 0x0612, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); + + bcm43xx_mac_enable(bcm); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + + bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED; +out: + return err; + +err_chip_cleanup: + bcm43xx_chip_cleanup(bcm); + goto out; +} + +static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) +{ + int err; + u16 pci_status; + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + +out: + return err; +} + +static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) +{ + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + bcm43xx_pctl_set_crystal(bcm, 0); +} + +static inline void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, + u32 address, + u32 data) +{ + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); +} + +static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) +{ + int err; + struct bcm43xx_coreinfo *old_core; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + + bcm43xx_switch_core(bcm, old_core); + assert(err == 0); +out: + return err; +} + +/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. + * To enable core 0, pass a core_mask of 1<<0 + */ +static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, + u32 core_mask) +{ + u32 backplane_flag_nr; + u32 value; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG); + backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + if (bcm->core_pci.rev < 6) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); + value |= (1 << backplane_flag_nr); + bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + value |= core_mask << 8; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + } + + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); + value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); + + if (bcm->core_pci.rev < 5) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); + err = bcm43xx_pcicore_commit_settings(bcm); + assert(err == 0); + } + +out_switch_back: + err = bcm43xx_switch_core(bcm, old_core); +out: + return err; +} + +static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) +{ + ieee80211softmac_start(bcm->net_dev); +} + +static void bcm43xx_periodic_work0_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + //TODO: unsigned int aci_average; + + spin_lock_irqsave(&bcm->lock, flags); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + //FIXME: aci_average = bcm43xx_update_aci_average(bcm); + if (bcm->current_core->radio->aci_enable && bcm->current_core->radio->aci_wlan_automatic) { + bcm43xx_mac_suspend(bcm); + if (!bcm->current_core->radio->aci_enable && + 1 /*FIXME: We are not scanning? */) { + /*FIXME: First add bcm43xx_update_aci_average() before + * uncommenting this: */ + //if (bcm43xx_radio_aci_scan) + // bcm43xx_radio_set_interference_mitigation(bcm, + // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } else if (1/*FIXME*/) { + //if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) + // bcm43xx_radio_set_interference_mitigation(bcm, + // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } + bcm43xx_mac_enable(bcm); + } else if (bcm->current_core->radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + if (bcm->current_core->phy->rev == 1) { + //FIXME: implement rev1 workaround + } + } + } + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, + BCM43xx_PERIODIC_0_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work1_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_phy_lo_mark_all_unused(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_mac_suspend(bcm); + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_mac_enable(bcm); + } + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, + BCM43xx_PERIODIC_1_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work2_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_G); + assert(bcm->current_core->phy->rev >= 2); + + bcm43xx_mac_suspend(bcm); + bcm43xx_phy_lo_g_measure(bcm); + bcm43xx_mac_enable(bcm); + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, + BCM43xx_PERIODIC_2_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work3_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + /* Update device statistics. */ + bcm43xx_calculate_link_quality(bcm); + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, + BCM43xx_PERIODIC_3_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* Delete all periodic tasks and make + * sure they are not running any longer + */ +static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) +{ + cancel_delayed_work(&bcm->periodic_work0); + cancel_delayed_work(&bcm->periodic_work1); + cancel_delayed_work(&bcm->periodic_work2); + cancel_delayed_work(&bcm->periodic_work3); + flush_workqueue(bcm->workqueue); +} + +/* Setup all periodic tasks. */ +static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) +{ + INIT_WORK(&bcm->periodic_work0, bcm43xx_periodic_work0_handler, bcm); + INIT_WORK(&bcm->periodic_work1, bcm43xx_periodic_work1_handler, bcm); + INIT_WORK(&bcm->periodic_work2, bcm43xx_periodic_work2_handler, bcm); + INIT_WORK(&bcm->periodic_work3, bcm43xx_periodic_work3_handler, bcm); + + /* Periodic task 0: Delay ~15sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, + BCM43xx_PERIODIC_0_DELAY); + + /* Periodic task 1: Delay ~60sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, + BCM43xx_PERIODIC_1_DELAY); + + /* Periodic task 2: Delay ~120sec */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + bcm->current_core->phy->rev >= 2) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, + BCM43xx_PERIODIC_2_DELAY); + } + + /* Periodic task 3: Delay ~30sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, + BCM43xx_PERIODIC_3_DELAY); +} + +static void bcm43xx_security_init(struct bcm43xx_private *bcm) +{ + bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, + 0x0056) * 2; + bcm43xx_clear_keys(bcm); +} + +/* This is the opposite of bcm43xx_init_board() */ +static void bcm43xx_free_board(struct bcm43xx_private *bcm) +{ + int i, err; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 0; + bcm->shutting_down = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + bcm43xx_periodic_tasks_delete(bcm); + + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) + continue; + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + continue; + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err == 0); + bcm43xx_wireless_core_cleanup(bcm); + } + + bcm43xx_pctl_set_crystal(bcm, 0); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->shutting_down = 0; + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static int bcm43xx_init_board(struct bcm43xx_private *bcm) +{ + int i, err; + int num_80211_cores; + int connect_phy; + unsigned long flags; + + might_sleep(); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 0; + bcm->shutting_down = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_crystal_off; + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); + if (err) + goto err_crystal_off; + + tasklet_enable(&bcm->isr_tasklet); + num_80211_cores = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < num_80211_cores; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + if (!bcm43xx_core_enabled(bcm)) { + if (num_80211_cores == 1) { + connect_phy = bcm->current_core->phy->connected; + } else { + if (i == 0) + connect_phy = 1; + else + connect_phy = 0; + } + bcm43xx_wireless_core_reset(bcm, connect_phy); + } + + if (i != 0) + bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); + + err = bcm43xx_wireless_core_init(bcm); + if (err) + goto err_80211_unwind; + + if (i != 0) { + bcm43xx_mac_suspend(bcm); + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + } + } + bcm->active_80211_core = &bcm->core_80211[0]; + if (num_80211_cores >= 2) { + bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + bcm43xx_mac_enable(bcm); + } + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); + dprintk(KERN_INFO PFX "80211 cores initialized\n"); + bcm43xx_security_init(bcm); + bcm43xx_softmac_init(bcm); + + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (bcm->current_core->radio->initial_channel != 0xFF) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); + bcm43xx_mac_enable(bcm); + } + bcm43xx_periodic_tasks_setup(bcm); + + assert(err == 0); +out: + return err; + +err_80211_unwind: + tasklet_disable(&bcm->isr_tasklet); + /* unwind all 80211 initialization */ + for (i = 0; i < num_80211_cores; i++) { + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + continue; + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_wireless_core_cleanup(bcm); + } +err_crystal_off: + bcm43xx_pctl_set_crystal(bcm, 0); + goto out; +} + +static void bcm43xx_detach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + int i; + + bcm43xx_chipset_detach(bcm); + /* Do _not_ access the chip, after it is detached. */ + iounmap(bcm->mmio_addr); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + + /* Free allocated structures/fields */ + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->phy[i]._lo_pairs); + if (bcm->phy[i].dyn_tssi_tbl) + kfree(bcm->phy[i].tssi2dbm); + } +} + +static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) +{ + u16 value; + u8 phy_version; + u8 phy_type; + u8 phy_rev; + int phy_rev_ok = 1; + void *p; + + value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); + + phy_version = (value & 0xF000) >> 12; + phy_type = (value & 0x0F00) >> 8; + phy_rev = (value & 0x000F); + + dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n", + phy_version, phy_type, phy_rev); + + switch (phy_type) { + case BCM43xx_PHYTYPE_A: + if (phy_rev >= 4) + phy_rev_ok = 0; + /*FIXME: We need to switch the ieee->modulation, etc.. flags, + * if we switch 80211 cores after init is done. + * As we do not implement on the fly switching between + * wireless cores, I will leave this as a future task. + */ + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION; + bcm->ieee->mode = IEEE_A; + bcm->ieee->freq_band = IEEE80211_52GHZ_BAND | + IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_B; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_G: + if (phy_rev > 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_G; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + default: + printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n", + phy_type); + return -ENODEV; + }; + if (!phy_rev_ok) { + printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", + phy_rev); + } + + bcm->current_core->phy->version = phy_version; + bcm->current_core->phy->type = phy_type; + bcm->current_core->phy->rev = phy_rev; + if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { + p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, + GFP_KERNEL); + if (!p) + return -ENOMEM; + bcm->current_core->phy->_lo_pairs = p; + } + + return 0; +} + +static int bcm43xx_attach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + struct net_device *net_dev = bcm->net_dev; + int err; + int i; + void __iomem *ioaddr; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + int num_80211_cores; + u32 coremask; + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); + err = -ENODEV; + goto out; + } + + mmio_start = pci_resource_start(pci_dev, 0); + mmio_end = pci_resource_end(pci_dev, 0); + mmio_flags = pci_resource_flags(pci_dev, 0); + mmio_len = pci_resource_len(pci_dev, 0); + + /* make sure PCI base addr is MMIO */ + if (!(mmio_flags & IORESOURCE_MEM)) { + printk(KERN_ERR PFX + "%s, region #0 not an MMIO resource, aborting\n", + pci_name(pci_dev)); + err = -ENODEV; + goto err_pci_disable; + } +//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there? +#ifndef CONFIG_BCM947XX + if (mmio_len != BCM43xx_IO_SIZE) { + printk(KERN_ERR PFX + "%s: invalid PCI mem region size(s), aborting\n", + pci_name(pci_dev)); + err = -ENODEV; + goto err_pci_disable; + } +#endif + + err = pci_request_regions(pci_dev, DRV_NAME); + if (err) { + printk(KERN_ERR PFX + "could not access PCI resources (%i)\n", err); + goto err_pci_disable; + } + + /* enable PCI bus-mastering */ + pci_set_master(pci_dev); + + /* ioremap MMIO region */ + ioaddr = ioremap(mmio_start, mmio_len); + if (!ioaddr) { + printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", + pci_name(pci_dev)); + err = -EIO; + goto err_pci_release; + } + + net_dev->base_addr = (unsigned long)ioaddr; + bcm->mmio_addr = ioaddr; + bcm->mmio_len = mmio_len; + + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + &bcm->board_vendor); + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + &bcm->board_type); + bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + &bcm->board_revision); + + err = bcm43xx_chipset_attach(bcm); + if (err) + goto err_iounmap; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_probe_cores(bcm); + if (err) + goto err_chipset_detach; + + num_80211_cores = bcm43xx_num_80211_cores(bcm); + + /* Attach all IO cores to the backplane. */ + coremask = 0; + for (i = 0; i < num_80211_cores; i++) + coremask |= (1 << bcm->core_80211[i].index); + //FIXME: Also attach some non80211 cores? + err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); + if (err) { + printk(KERN_ERR PFX "Backplane->PCI connection failed!\n"); + goto err_chipset_detach; + } + + err = bcm43xx_read_sprom(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_leds_init(bcm); + if (err) + goto err_chipset_detach; + + for (i = 0; i < num_80211_cores; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + bcm43xx_wireless_core_reset(bcm, (i == 0)); + + err = bcm43xx_read_phyinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_read_radioinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_validate_chip(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + bcm43xx_radio_turn_off(bcm); + err = bcm43xx_phy_init_tssi2dbm_table(bcm); + if (err) + goto err_80211_unwind; + bcm43xx_wireless_core_disable(bcm); + } + bcm43xx_pctl_set_crystal(bcm, 0); + + /* Set the MAC address in the networking subsystem */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); + else + memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); + + bcm43xx_geo_init(bcm); + + snprintf(bcm->nick, IW_ESSID_MAX_SIZE, + "Broadcom %04X", bcm->chip_id); + + assert(err == 0); +out: + return err; + +err_80211_unwind: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->phy[i]._lo_pairs); + if (bcm->phy[i].dyn_tssi_tbl) + kfree(bcm->phy[i].tssi2dbm); + } +err_chipset_detach: + bcm43xx_chipset_detach(bcm); +err_iounmap: + iounmap(bcm->mmio_addr); +err_pci_release: + pci_release_regions(pci_dev); +err_pci_disable: + pci_disable_device(pci_dev); + goto out; +} + +static inline +s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, + int ofdm, int adjust_2053, int adjust_2050) +{ + s32 tmp; + + switch (bcm->current_core->radio->version) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = bcm->current_core->radio->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +static inline +s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) +{ + s8 ret; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); + + return ret; +} + +static inline +int bcm43xx_rx_packet(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct ieee80211_rx_stats *stats) +{ + int err; + + err = ieee80211_rx(bcm->ieee, skb, stats); + if (unlikely(err == 0)) + return -EINVAL; + return 0; +} + +int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) +{ + struct bcm43xx_plcp_hdr4 *plcp; + struct ieee80211_rx_stats stats; + struct ieee80211_hdr_4addr *wlhdr; + u16 frame_ctl; + int is_packet_for_us = 0; + int err = -EINVAL; + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); + + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); + /* Skip two unknown bytes and the PLCP header. */ + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); + } else { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); + /* Skip the PLCP header. */ + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); + } + /* The SKB contains the PAYLOAD (wireless header + data) + * at this point. The FCS at the end is stripped. + */ + + memset(&stats, 0, sizeof(stats)); + stats.mac_time = le16_to_cpu(rxhdr->mactime); + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); + stats.signal = rxhdr->signal_quality; //FIXME +//TODO stats.noise = + stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm); +//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); + stats.received_channel = bcm->current_core->radio->channel; +//TODO stats.control = + stats.mask = IEEE80211_STATMASK_SIGNAL | +//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_RATE | + IEEE80211_STATMASK_RSSI; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + stats.freq = IEEE80211_52GHZ_BAND; + else + stats.freq = IEEE80211_24GHZ_BAND; + stats.len = skb->len; + + bcm->stats.last_rx = jiffies; + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) + return bcm43xx_rx_packet(bcm, skb, &stats); + + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + break; + case IW_MODE_INFRA: + default: + /* When receiving multicast or broadcast packets, filter out + the packets we send ourself; we shouldn't see those */ + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && + (is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC))) + is_packet_for_us = 1; + break; + } + + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); + + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); + /* trim IV and ICV */ + /* FIXME: this must be done only for WEP encrypted packets */ + if (skb->len < 32) { + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " + "set and length < 32)\n"); + return -EINVAL; + } else { + memmove(skb->data + 4, skb->data, 24); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + stats.len -= 8; + } + /* do _not_ use wlhdr again without reassigning it */ + } + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(bcm->ieee, skb->data, &stats); + break; + case IEEE80211_FTYPE_DATA: + if (is_packet_for_us) + err = bcm43xx_rx_packet(bcm, skb, &stats); + break; + case IEEE80211_FTYPE_CTL: + break; + default: + assert(0); + return -EINVAL; + } + + return err; +} + +/* Do the Hardware IO operations to send the txb */ +static inline int bcm43xx_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + int err = -ENODEV; + + if (bcm->pio_mode) + err = bcm43xx_pio_transfer_txb(bcm, txb); + else + err = bcm43xx_dma_transfer_txb(bcm, txb); + + return err; +} + +static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, + u8 channel) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* set_security() callback in struct ieee80211_device */ +static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, + struct ieee80211_security *sec) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211_security *secinfo = &bcm->ieee->sec; + unsigned long flags; + int keyidx; + + dprintk(KERN_INFO PFX "set security called\n"); + + spin_lock_irqsave(&bcm->lock, flags); + + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx] = sec->encode_alg[keyidx]; + secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; + memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN); + } + + if (sec->flags & SEC_ACTIVE_KEY) { + secinfo->active_key = sec->active_key; + dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key); + } + if (sec->flags & SEC_UNICAST_GROUP) { + secinfo->unicast_uses_group = sec->unicast_uses_group; + dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group); + } + if (sec->flags & SEC_LEVEL) { + secinfo->level = sec->level; + dprintk(KERN_INFO PFX " .level = %d\n", sec->level); + } + if (sec->flags & SEC_ENABLED) { + secinfo->enabled = sec->enabled; + dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled); + } + if (sec->flags & SEC_ENCRYPT) { + secinfo->encrypt = sec->encrypt; + dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt); + } + if (bcm->initialized && !bcm->ieee->host_encrypt) { + if (secinfo->enabled) { + /* upload WEP keys to hardware */ + char null_address[6] = { 0 }; + u8 algorithm = 0; + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx]) { + case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break; + case SEC_ALG_WEP: + algorithm = BCM43xx_SEC_ALGO_WEP; + if (secinfo->key_sizes[keyidx] == 13) + algorithm = BCM43xx_SEC_ALGO_WEP104; + break; + case SEC_ALG_TKIP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_TKIP; + break; + case SEC_ALG_CCMP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_AES; + break; + default: + assert(0); + break; + } + bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]); + bcm->key[keyidx].enabled = 1; + bcm->key[keyidx].algorithm = algorithm; + } + } else + bcm43xx_clear_keys(bcm); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* hard_start_xmit() callback in struct ieee80211_device */ +static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, + struct net_device *net_dev, + int pri) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -ENODEV; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (likely(bcm->initialized)) + err = bcm43xx_tx(bcm, txb); + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) +{ + return &(bcm43xx_priv(net_dev)->ieee->stats); +} + +static void bcm43xx_net_tx_timeout(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + bcm43xx_controller_restart(bcm, "TX timeout"); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void bcm43xx_net_poll_controller(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + local_irq_save(flags); + bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); + local_irq_restore(flags); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static int bcm43xx_net_open(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + return bcm43xx_init_board(bcm); +} + +static int bcm43xx_net_stop(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + ieee80211softmac_stop(net_dev); + bcm43xx_disable_interrupts_sync(bcm, NULL); + bcm43xx_free_board(bcm); + + return 0; +} + +static void bcm43xx_init_private(struct bcm43xx_private *bcm, + struct net_device *net_dev, + struct pci_dev *pci_dev, + struct workqueue_struct *wq) +{ + bcm->ieee = netdev_priv(net_dev); + bcm->softmac = ieee80211_priv(net_dev); + bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; + bcm->workqueue = wq; + +#ifdef DEBUG_ENABLE_MMIO_PRINT + bcm43xx_mmioprint_initial(bcm, 1); +#else + bcm43xx_mmioprint_initial(bcm, 0); +#endif +#ifdef DEBUG_ENABLE_PCILOG + bcm43xx_pciprint_initial(bcm, 1); +#else + bcm43xx_pciprint_initial(bcm, 0); +#endif + + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + bcm->pci_dev = pci_dev; + bcm->net_dev = net_dev; + if (modparam_bad_frames_preempt) + bcm->bad_frames_preempt = 1; + spin_lock_init(&bcm->lock); + tasklet_init(&bcm->isr_tasklet, + (void (*)(unsigned long))bcm43xx_interrupt_tasklet, + (unsigned long)bcm); + tasklet_disable_nosync(&bcm->isr_tasklet); + if (modparam_pio) { + bcm->pio_mode = 1; + } else { + if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) { + bcm->pio_mode = 0; + } else { + printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); + bcm->pio_mode = 1; + } + } + bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; + + /* default to sw encryption for now */ + bcm->ieee->host_build_iv = 0; + bcm->ieee->host_encrypt = 1; + bcm->ieee->host_decrypt = 1; + + bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE; + bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); + bcm->ieee->set_security = bcm43xx_ieee80211_set_security; + bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; +} + +static int __devinit bcm43xx_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *net_dev; + struct bcm43xx_private *bcm; + struct workqueue_struct *wq; + int err; + +#ifdef CONFIG_BCM947XX + if ((pdev->bus->number == 0) && (pdev->device != 0x0800)) + return -ENODEV; +#endif + +#ifdef DEBUG_SINGLE_DEVICE_ONLY + if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY)) + return -ENODEV; +#endif + + net_dev = alloc_ieee80211softmac(sizeof(*bcm)); + if (!net_dev) { + printk(KERN_ERR PFX + "could not allocate ieee80211 device %s\n", + pci_name(pdev)); + err = -ENOMEM; + goto out; + } + /* initialize the net_device struct */ + SET_MODULE_OWNER(net_dev); + SET_NETDEV_DEV(net_dev, &pdev->dev); + + net_dev->open = bcm43xx_net_open; + net_dev->stop = bcm43xx_net_stop; + net_dev->get_stats = bcm43xx_net_get_stats; + net_dev->tx_timeout = bcm43xx_net_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = bcm43xx_net_poll_controller; +#endif + net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; + net_dev->irq = pdev->irq; + net_dev->watchdog_timeo = BCM43xx_TX_TIMEOUT; + + /* initialize the bcm43xx_private struct */ + bcm = bcm43xx_priv(net_dev); + memset(bcm, 0, sizeof(*bcm)); + wq = create_workqueue(DRV_NAME "_wq"); + if (!wq) { + err = -ENOMEM; + goto err_free_netdev; + } + bcm43xx_init_private(bcm, net_dev, pdev, wq); + + pci_set_drvdata(pdev, net_dev); + + err = bcm43xx_attach_board(bcm); + if (err) + goto err_destroy_wq; + + err = register_netdev(net_dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + err = -ENOMEM; + goto err_detach_board; + } + + bcm43xx_debugfs_add_device(bcm); + + assert(err == 0); +out: + return err; + +err_detach_board: + bcm43xx_detach_board(bcm); +err_destroy_wq: + destroy_workqueue(wq); +err_free_netdev: + free_ieee80211softmac(net_dev); + goto out; +} + +static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + bcm43xx_debugfs_remove_device(bcm); + unregister_netdev(net_dev); + bcm43xx_detach_board(bcm); + assert(bcm->ucode == NULL); + destroy_workqueue(bcm->workqueue); + free_ieee80211softmac(net_dev); +} + +/* Hard-reset the chip. Do not call this directly. + * Use bcm43xx_controller_restart() + */ +static void bcm43xx_chip_reset(void *_bcm) +{ + struct bcm43xx_private *bcm = _bcm; + struct net_device *net_dev = bcm->net_dev; + struct pci_dev *pci_dev = bcm->pci_dev; + struct workqueue_struct *wq = bcm->workqueue; + int err; + int was_initialized = bcm->initialized; + + netif_stop_queue(bcm->net_dev); + tasklet_disable(&bcm->isr_tasklet); + + bcm->firmware_norelease = 1; + if (was_initialized) + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + bcm43xx_detach_board(bcm); + bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_attach_board(bcm); + if (err) + goto failure; + if (was_initialized) { + err = bcm43xx_init_board(bcm); + if (err) + goto failure; + } + netif_wake_queue(bcm->net_dev); + printk(KERN_INFO PFX "Controller restarted\n"); + + return; +failure: + printk(KERN_ERR PFX "Controller restart failed\n"); +} + +/* Hard-reset the chip. + * This can be called from interrupt or process context. + * Make sure to _not_ re-enable device interrupts after this has been called. +*/ +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) +{ + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); + queue_work(bcm->workqueue, &bcm->restart_work); +} + +#ifdef CONFIG_PM + +static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int try_to_shutdown = 0, err; + + dprintk(KERN_INFO PFX "Suspending...\n"); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->was_initialized = bcm->initialized; + if (bcm->initialized) + try_to_shutdown = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + netif_device_detach(net_dev); + if (try_to_shutdown) { + ieee80211softmac_stop(net_dev); + err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "Suspend failed.\n"); + return -EAGAIN; + } + bcm->firmware_norelease = 1; + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + } + bcm43xx_chipset_detach(bcm); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + dprintk(KERN_INFO PFX "Device suspended.\n"); + + return 0; +} + +static int bcm43xx_resume(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = 0; + + dprintk(KERN_INFO PFX "Resuming...\n"); + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + bcm43xx_chipset_attach(bcm); + if (bcm->was_initialized) { + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + err = bcm43xx_init_board(bcm); + } + if (err) { + printk(KERN_ERR PFX "Resume failed!\n"); + return err; + } + + netif_device_attach(net_dev); + + /*FIXME: This should be handled by softmac instead. */ + schedule_work(&bcm->softmac->associnfo.work); + + dprintk(KERN_INFO PFX "Device resumed.\n"); + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver bcm43xx_pci_driver = { + .name = BCM43xx_DRIVER_NAME, + .id_table = bcm43xx_pci_tbl, + .probe = bcm43xx_init_one, + .remove = __devexit_p(bcm43xx_remove_one), +#ifdef CONFIG_PM + .suspend = bcm43xx_suspend, + .resume = bcm43xx_resume, +#endif /* CONFIG_PM */ +}; + +static int __init bcm43xx_init(void) +{ + printk(KERN_INFO BCM43xx_DRIVER_NAME "\n"); + bcm43xx_debugfs_init(); + return pci_register_driver(&bcm43xx_pci_driver); +} + +static void __exit bcm43xx_exit(void) +{ + pci_unregister_driver(&bcm43xx_pci_driver); + bcm43xx_debugfs_exit(); +} + +module_init(bcm43xx_init) +module_exit(bcm43xx_exit) + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h new file mode 100644 index 00000000000..1d3eddd314b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -0,0 +1,283 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_MAIN_H_ +#define BCM43xx_MAIN_H_ + +#include "bcm43xx.h" + +#ifdef CONFIG_BCM947XX +#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) + +static inline void e_aton(char *str, char *dest) +{ + int i = 0; + u16 *d = (u16 *) dest; + + for (;;) { + dest[i++] = (char) simple_strtoul(str, NULL, 16); + str += 2; + if (!*str++ || i == 6) + break; + } + for (i = 0; i < 3; i++) + d[i] = cpu_to_be16(d[i]); +} +#endif + + +#define _bcm43xx_declare_plcp_hdr(size) \ + struct bcm43xx_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct bcm43xx_plcp_hdr4 */ +_bcm43xx_declare_plcp_hdr(4); +/* struct bcm430c_plcp_hdr6 */ +_bcm43xx_declare_plcp_hdr(6); + +#undef _bcm43xx_declare_plcp_hdr + + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + + +/* Device specific TX header. To be prepended to TX frames. */ +struct bcm43xx_txhdr { + union { + struct { + u16 flags; + u16 wsec_rate; + u16 frame_control; + u16 unknown_zeroed_0; + u16 control; + unsigned char wep_iv[10]; + unsigned char unknown_wsec_tkip_data[3]; //FIXME + PAD_BYTES(3); + unsigned char mac1[6]; + u16 unknown_zeroed_1; + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; + u16 rts_cts_dur_fallback; + struct bcm43xx_plcp_hdr4 fallback_plcp; + u16 fallback_dur_id; + PAD_BYTES(2); + u16 cookie; + u16 unknown_scb_stuff; //FIXME + struct bcm43xx_plcp_hdr6 rts_cts_plcp; + u16 rts_cts_frame_type; + u16 rts_cts_dur; + unsigned char rts_cts_mac1[6]; + unsigned char rts_cts_mac2[6]; + PAD_BYTES(2); + struct bcm43xx_plcp_hdr6 plcp; + } __attribute__((__packed__)); + + unsigned char raw[82]; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + +struct sk_buff; + +void FASTCALL(bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie)); + +/* RX header as received from the hardware. */ +struct bcm43xx_rxhdr { + /* Frame Length. Must be generated explicitely in PIO mode. */ + __le16 frame_length; + PAD_BYTES(2); + /* Flags field 1 */ + __le16 flags1; + u8 rssi; + u8 signal_quality; + PAD_BYTES(2); + /* Flags field 3 */ + __le16 flags3; + /* Flags field 2 */ + __le16 flags2; + /* Lower 16bits of the TSF at the time the frame started. */ + __le16 mactime; + PAD_BYTES(14); +} __attribute__((__packed__)); + +#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) +/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ +#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) +#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) + +#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) +#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) +/*FIXME: WEP related flags */ + +#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) + +/* Transmit Status as received from the hardware. */ +struct bcm43xx_hwxmitstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + PAD_BYTES(2); + __le16 seq; + __le16 unknown; //FIXME +} __attribute__((__packed__)); + +/* Transmit Status in CPU byteorder. */ +struct bcm43xx_xmitstatus { + u16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + u16 seq; + u16 unknown; //FIXME +}; + +#define BCM43xx_TXSTAT_FLAG_ACK 0x01 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 +#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 + +struct bcm43xx_xmitstatus_queue { + struct list_head list; + struct bcm43xx_hwxmitstatus status; +}; + + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline +u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, + int freq) +{ + u8 channel; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + channel = (freq - 5000) / 5; + } else { + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + } + + return channel; +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline +int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, + u8 channel) +{ + int freq; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + freq = 5000 + (5 * channel); + } else { + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + } + + return freq; +} + +/* Lightweight function to check if a channel number is valid. + * Note that this does _NOT_ check for geographical restrictions! + */ +static inline +int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (channel <= 200) + return 1; + } else { + if (channel >= 1 && channel <= 14) + return 1; + } + + return 0; +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); + +int FASTCALL(bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr)); + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode); + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value); +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value); + +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); + +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); + +int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val); +int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val); +int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val); +int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); + +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); +void bcm43xx_mac_enable(struct bcm43xx_private *bcm); + +u8 bcm43xx_sprom_crc(const u16 *sprom); + +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); + +#endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c new file mode 100644 index 00000000000..41b9cd7fc9e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -0,0 +1,2122 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_power.h" + + +static const s8 bcm43xx_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 bcm43xx_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); + + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + assert(irqs_disabled()); + if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { + phy->is_locked = 0; + return; + } + if (bcm->current_core->rev < 3) { + bcm43xx_mac_suspend(bcm); + spin_lock(&phy->lock); + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + } + phy->is_locked = 1; +} + +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + assert(irqs_disabled()); + if (bcm->current_core->rev < 3) { + if (phy->is_locked) { + spin_unlock(&phy->lock); + bcm43xx_mac_enable(bcm); + } + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + phy->is_locked = 0; +} + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA); +} + +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); +} + +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + unsigned long flags; + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ + if (phy->calibrated) + return; + if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + bcm43xx_wireless_core_reset(bcm, 0); + bcm43xx_phy_initg(bcm); + bcm43xx_wireless_core_reset(bcm, 1); + + local_irq_restore(flags); + } + phy->calibrated = 1; +} + +/* Connect the PHY + * http://bcm-specs.sipsolutions.net/SetPHY + */ +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) +{ + u32 flags; + + if (bcm->current_core->rev < 5) { + if (connect) { + bcm->current_core->phy->connected = 1; + dprintk(KERN_INFO PFX "PHY connected\n"); + } else { + bcm->current_core->phy->connected = 0; + dprintk(KERN_INFO PFX "PHY disconnected\n"); + } + return 0; + } + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (connect) { + if (!(flags & 0x00010000)) + return -ENODEV; + bcm->current_core->phy->connected = 1; + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags |= (0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + dprintk(KERN_INFO PFX "PHY connected\n"); + } else { + if (!(flags & 0x00020000)) + return -ENODEV; + bcm->current_core->phy->connected = 0; + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags &= ~(0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + dprintk(KERN_INFO PFX "PHY disconnected\n"); + } + + return 0; +} + +/* intialize B PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; + int must_reset_txpower = 0; + + assert(phy->type != BCM43xx_PHYTYPE_A); + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416)) + return; + + bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); + bcm43xx_phy_write(bcm, 0x0028, 0x8018); + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (!phy->connected) + return; + bcm43xx_phy_write(bcm, 0x047A, 0xC111); + } + if (phy->savedpctlreg != 0xFFFF) + return; + + if (phy->type == BCM43xx_PHYTYPE_B && + phy->rev >= 2 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0076, + bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); + } else { + saved_batt = radio->txpower[0]; + saved_ratt = radio->txpower[1]; + saved_txctl1 = radio->txpower[2]; + if ((radio->revision >= 6) && (radio->revision <= 8) + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); + else + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0); + must_reset_txpower = 1; + } + bcm43xx_dummy_transmission(bcm); + + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL); + + if (must_reset_txpower) + bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1); + else + bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B); + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + bcm43xx_ilt_write16(bcm, offset, 0x00FE); + bcm43xx_ilt_write16(bcm, offset + 1, 0x000D); + bcm43xx_ilt_write16(bcm, offset + 2, 0x0013); + bcm43xx_ilt_write16(bcm, offset + 3, 0x0019); + + if (phy->rev == 1) { + bcm43xx_ilt_write16(bcm, 0x1800, 0x2710); + bcm43xx_ilt_write16(bcm, 0x1801, 0x9B83); + bcm43xx_ilt_write16(bcm, 0x1802, 0x9B83); + bcm43xx_ilt_write16(bcm, 0x1803, 0x0F8D); + bcm43xx_phy_write(bcm, 0x0455, 0x0004); + } + + bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008); + + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008); + bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700); + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100); + + if (phy->rev == 1) + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007); + + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0430, 0x092B); + bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002); + } else { + bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1); + bcm43xx_phy_write(bcm, 0x041F, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004); + } + + if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x0422, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); + } + + bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); + bcm43xx_phy_write(bcm, 0x048E, 0x1C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x048B, 0x005E); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); + bcm43xx_phy_write(bcm, 0x048D, 0x0002); + } + + bcm43xx_ilt_write16(bcm, offset + 0x0800, 0); + bcm43xx_ilt_write16(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write16(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write16(bcm, offset + 0x0803, 28); +} + +static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i; + + assert(phy->type == BCM43xx_PHYTYPE_G); + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0406, 0x4F19); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); + bcm43xx_phy_write(bcm, 0x042C, 0x005A); + bcm43xx_phy_write(bcm, 0x0427, 0x001A); + + for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); + for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); + + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x1861); + bcm43xx_phy_write(bcm, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x0098); + bcm43xx_phy_write(bcm, 0x04C1, 0x0070); + bcm43xx_phy_write(bcm, 0x04C9, 0x0080); + } + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); + else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); + else + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 7)) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + for (i = 0; i < 4; i++) { + bcm43xx_ilt_write16(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x5408 + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x540C + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x5410 + i, 0x0020); + } + bcm43xx_phy_agcsetup(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write16(bcm, 0x5001, 0x0002); + bcm43xx_ilt_write16(bcm, 0x5002, 0x0001); + } else { + for (i = 0; i <= 0x2F; i++) + bcm43xx_ilt_write16(bcm, 0x1000 + i, 0x0820); + bcm43xx_phy_agcsetup(bcm); + bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0403, 0x1000); + bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write16(bcm, 0x0401, 0x0002); + bcm43xx_ilt_write16(bcm, 0x0402, 0x0001); + } +} + +/* Initialize the noisescaletable for APHY */ +static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + int i; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); + for (i = 0; i < 12; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300); + for (i = 0; i < 11; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023); +} + +static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) +{ + u16 i; + + assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_A); + switch (bcm->current_core->phy->rev) { + case 2: + bcm43xx_phy_write(bcm, 0x008E, 0x3800); + bcm43xx_phy_write(bcm, 0x0035, 0x03FF); + bcm43xx_phy_write(bcm, 0x0036, 0x0400); + + bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_ilt_write16(bcm, 0x3C0C, 0x07BF); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); + bcm43xx_phy_write(bcm, 0x008E, 0x58C1); + + bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + + for (i = 0; i < 16; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, (0x8 + i) & 0x000F); + + bcm43xx_ilt_write16(bcm, 0x3003, 0x1044); + bcm43xx_ilt_write16(bcm, 0x3004, 0x7201); + bcm43xx_ilt_write16(bcm, 0x3006, 0x0040); + bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + + for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); + for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + + bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + + bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + + bcm43xx_phy_write(bcm, 0x0003, 0x1808); + + bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + + bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + break; + default: + assert(0); + } +} + +/* Initialize APHY. This is also called for the GPHY in some cases. */ +static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 tval; + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_phy_setupa(bcm); + } else { + bcm43xx_phy_setupg(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x046E, 0x03CF); + return; + } + + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340); + bcm43xx_phy_write(bcm, 0x0034, 0x0001); + + TODO();//TODO: RSSI AGC + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14)); + bcm43xx_radio_init2060(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) + && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { + if (bcm->current_core->radio->lofcal == 0xFFFF) { + TODO();//TODO: LOF Cal + bcm43xx_radio_set_tx_iq(bcm); + } else + bcm43xx_radio_write16(bcm, 0x001E, bcm->current_core->radio->lofcal); + } + + bcm43xx_phy_write(bcm, 0x007A, 0xF111); + + if (phy->savedpctlreg == 0xFFFF) { + bcm43xx_radio_write16(bcm, 0x0019, 0x0000); + bcm43xx_radio_write16(bcm, 0x0017, 0x0020); + + tval = bcm43xx_ilt_read16(bcm, 0x3001); + if (phy->rev == 1) { + bcm43xx_ilt_write16(bcm, 0x3001, + (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFF87) + | 0x0058); + } else { + bcm43xx_ilt_write16(bcm, 0x3001, + (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFFC3) + | 0x002C); + } + bcm43xx_dummy_transmission(bcm); + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); + bcm43xx_ilt_write16(bcm, 0x3001, tval); + + bcm43xx_radio_set_txpower_a(bcm, 0x0018); + } + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x0032, 0x00CC); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + bcm43xx_phy_lo_b_measure(bcm); + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0032, 0x00E0); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + + bcm43xx_phy_lo_b_measure(bcm); + + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset; + + if (phy->version == 1 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0050); + } + if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type != 0x0416)) { + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { + bcm43xx_phy_write(bcm, offset, + (bcm43xx_phy_read(bcm, offset) + 0x2020) + & 0x3F3F); + } + } + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF) + | 0x0700); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0038, 0x0667); + + if (phy->connected) { + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) + | 0x0004); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000); + + bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + + bcm43xx_phy_write(bcm, 0x001C, 0x186A); + + bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900); + bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064); + bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A); + } + + if (bcm->bad_frames_preempt) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->version == 1 && radio->version == 0x2050) { + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_phy_write(bcm, 0x0021, 0x3763); + bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); + bcm43xx_phy_write(bcm, 0x0023, 0x06F9); + bcm43xx_phy_write(bcm, 0x0024, 0x037E); + } else + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + + if (phy->version == 1 && radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); + else + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + + if (phy->version == 0) + bcm43xx_write16(bcm, 0x03E4, 0x3000); + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + } + + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x88A3, 0x002A); + + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + + if (radio->version == 0x2050) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + + bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_phy_write(bcm, 0x003E, 0x817A); + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x001F); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x005B); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x0088); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 6)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x008B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B5); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 7)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x00A8); + bcm43xx_radio_write16(bcm, 0x005C, 0x0075); + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + bcm43xx_radio_write16(bcm, 0x007D, 0x00E8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + bcm43xx_radio_write16(bcm, 0x007B, 0x0000); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 8)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x006B); + bcm43xx_radio_write16(bcm, 0x005C, 0x000F); + if (bcm->sprom.boardflags & 0x8000) { + bcm43xx_radio_write16(bcm, 0x005D, 0x00FA); + bcm43xx_radio_write16(bcm, 0x005E, 0x00D8); + } else { + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + } + bcm43xx_radio_write16(bcm, 0x0073, 0x0003); + bcm43xx_radio_write16(bcm, 0x007D, 0x00A8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + bcm43xx_phy_write(bcm, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == BCM43xx_PHYTYPE_G) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + } + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + udelay(40); + bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + if ((bcm->current_core->radio->manufact == 0x17F) && + (bcm->current_core->radio->version == 0x2050) && + (bcm->current_core->radio->revision == 2)) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + } + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0200); + if (radio->version == 0x2050){ + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); + else + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + } + bcm43xx_phy_write(bcm, 0x0038, 0x0668); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (radio->version == 0x2050) { + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); + else if (radio->revision <= 2) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + } + + if (phy->rev == 4) + bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); + else + bcm43xx_write16(bcm, 0x03E4, 0x0009); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_write16(bcm, 0x03E6, 0x8140); + bcm43xx_phy_write(bcm, 0x0016, 0x5410); + bcm43xx_phy_write(bcm, 0x0017, 0xA820); + bcm43xx_phy_write(bcm, 0x0007, 0x0062); + TODO();//TODO: calibrate stuff. + bcm43xx_phy_init_pctl(bcm); + } else + bcm43xx_write16(bcm, 0x03E6, 0x0); +} + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 tmp; + + if (phy->rev == 1) + bcm43xx_phy_initb5(bcm); + else if (phy->rev >= 2 && phy->rev <= 7) + bcm43xx_phy_initb6(bcm); + if (phy->rev >= 2 || phy->connected) + bcm43xx_phy_inita(bcm); + + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0814, 0x0000); + bcm43xx_phy_write(bcm, 0x0815, 0x0000); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0811, 0x0000); + else if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x0811, 0x0400); + bcm43xx_phy_write(bcm, 0x0015, 0x00C0); + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; + if (tmp == 3) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8606); + } else if (tmp == 4 || tmp == 5) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); + bcm43xx_phy_write(bcm, 0x04CC, (bcm43xx_phy_read(bcm, 0x04CC) + & 0x00FF) | 0x1F00); + } + } + if (radio->revision <= 3 && phy->connected) + bcm43xx_phy_write(bcm, 0x047E, 0x0078); + if (radio->revision >= 6 && radio->revision <= 8) { + bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); + bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); + } + if (radio->initval == 0xFFFF) { + radio->initval = bcm43xx_radio_init2050(bcm); + bcm43xx_phy_lo_g_measure(bcm); + } else { + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) + | radio->txpower[3]); + } + + if (phy->connected) { + bcm43xx_phy_lo_adjust(bcm, 0); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x002E, 0x807F); + else + bcm43xx_phy_write(bcm, 0x002E, 0x8075); + + if (phy->rev < 2) + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + } + + if ((bcm->sprom.boardflags & BCM43xx_BFL_RSSI) == 0) { + FIXME();//FIXME: 0x7FFFFFFF should be 16-bit ! + bcm43xx_nrssi_hw_update(bcm, (u16)0x7FFFFFFF); + bcm43xx_calc_nrssi_threshold(bcm); + } else if (phy->connected) { + if (radio->nrssi[0] == -1000) { + assert(radio->nrssi[1] == -1000); + bcm43xx_calc_nrssi_slope(bcm); + } else + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +} + +static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) +{ + int i; + u16 ret = 0; + + for (i = 0; i < 10; i++){ + bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); + udelay(1); + bcm43xx_phy_write(bcm, 0x0015, 0xEFA0); + udelay(10); + bcm43xx_phy_write(bcm, 0x0015, 0xFFA0); + udelay(40); + ret += bcm43xx_phy_read(bcm, 0x002C); + } + + return ret; +} + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i, j; + + regstack[0] = bcm43xx_phy_read(bcm, 0x0015); + regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0; + + if (radio->version == 0x2053) { + regstack[2] = bcm43xx_phy_read(bcm, 0x000A); + regstack[3] = bcm43xx_phy_read(bcm, 0x002A); + regstack[4] = bcm43xx_phy_read(bcm, 0x0035); + regstack[5] = bcm43xx_phy_read(bcm, 0x0003); + regstack[6] = bcm43xx_phy_read(bcm, 0x0001); + regstack[7] = bcm43xx_phy_read(bcm, 0x0030); + + regstack[8] = bcm43xx_radio_read16(bcm, 0x0043); + regstack[9] = bcm43xx_radio_read16(bcm, 0x007A); + regstack[10] = bcm43xx_read16(bcm, 0x03EC); + regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0; + + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0); + } + bcm43xx_phy_write(bcm, 0x0015, 0xB000); + bcm43xx_phy_write(bcm, 0x002B, 0x0004); + + if (radio->version == 0x2053) { + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + bcm43xx_phy_lo_b_r15_loop(bcm); + } + for (i = 0; i < 10; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + bcm43xx_phy_write(bcm, 0x002F, fval); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); + if (radio->version == 2053) { + bcm43xx_phy_write(bcm, 0x000A, regstack[2]); + bcm43xx_phy_write(bcm, 0x002A, regstack[3]); + bcm43xx_phy_write(bcm, 0x0035, regstack[4]); + bcm43xx_phy_write(bcm, 0x0003, regstack[5]); + bcm43xx_phy_write(bcm, 0x0001, regstack[6]); + bcm43xx_phy_write(bcm, 0x0030, regstack[7]); + + bcm43xx_radio_write16(bcm, 0x0043, regstack[8]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9]); + + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F) + | regstack[11]); + + bcm43xx_write16(bcm, 0x03EC, regstack[10]); + } + bcm43xx_phy_write(bcm, 0x0015, regstack[0]); +} + +static inline +u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) +{ + if (bcm->current_core->phy->connected) { + bcm43xx_phy_write(bcm, 0x15, 0xE300); + control <<= 8; + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, 0xF300); + udelay(8); + } else { + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0); + udelay(2); + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); + udelay(8); + } + + return bcm43xx_phy_read(bcm, 0x002D); +} + +static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) +{ + int i; + u32 ret = 0; + + for (i = 0; i < 8; i++) + ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control); + + return ret; +} + +/* Write the LocalOscillator CONTROL */ +static inline +void bcm43xx_lo_write(struct bcm43xx_private *bcm, + struct bcm43xx_lopair *pair) +{ + u16 value; + + value = (u8)(pair->low); + value |= ((u8)(pair->high)) << 8; + +#ifdef CONFIG_BCM43XX_DEBUG + /* Sanity check. */ + if (pair->low < -8 || pair->low > 8 || + pair->high < -8 || pair->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Writing invalid LOpair " + "(low: %d, high: %d, index: %lu)\n", + pair->low, pair->high, + (unsigned long)(pair - bcm->current_core->phy->_lo_pairs)); + dump_stack(); + } +#endif + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value); +} + +static inline +struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, + u16 baseband_attenuation, + u16 radio_attenuation, + u16 tx) +{ + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (baseband_attenuation > 6) + baseband_attenuation = 6; + assert(radio_attenuation < 10); + assert(tx == 0 || tx == 3); + + if (tx == 3) { + return bcm43xx_get_lopair(phy, + radio_attenuation, + baseband_attenuation); + } + return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation); +} + +static inline +struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) +{ + return bcm43xx_find_lopair(bcm, + bcm->current_core->radio->txpower[0], + bcm->current_core->radio->txpower[1], + bcm->current_core->radio->txpower[2]); +} + +/* Adjust B/G LO */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) +{ + struct bcm43xx_lopair *pair; + + if (fixed) { + /* Use fixed values. Only for initialization. */ + pair = bcm43xx_find_lopair(bcm, 2, 3, 0); + } else + pair = bcm43xx_current_lopair(bcm); + bcm43xx_lo_write(bcm, pair); +} + +static inline +void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) +{ + u16 txctl2 = 0, i; + u32 smallest, tmp; + + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + udelay(10); + smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0052, i); + udelay(10); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + if (tmp < smallest) { + smallest = tmp; + txctl2 = i; + } + } + bcm->current_core->radio->txpower[3] = txctl2; +} + +static +void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, + const struct bcm43xx_lopair *in_pair, + struct bcm43xx_lopair *out_pair, + u16 r27) +{ + static const struct bcm43xx_lopair transitions[8] = { + { .high = 1, .low = 1, }, + { .high = 1, .low = 0, }, + { .high = 1, .low = -1, }, + { .high = 0, .low = -1, }, + { .high = -1, .low = -1, }, + { .high = -1, .low = 0, }, + { .high = -1, .low = 1, }, + { .high = 0, .low = 1, }, + }; + struct bcm43xx_lopair lowest_transition = { + .high = in_pair->high, + .low = in_pair->low, + }; + struct bcm43xx_lopair tmp_pair; + struct bcm43xx_lopair transition; + int i = 12; + int state = 0; + int found_lower; + int j, begin, end; + u32 lowest_deviation; + u32 tmp; + + /* Note that in_pair and out_pair can point to the same pair. Be careful. */ + + bcm43xx_lo_write(bcm, &lowest_transition); + lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + do { + found_lower = 0; + assert(state >= 0 && state <= 8); + if (state == 0) { + begin = 1; + end = 8; + } else if (state % 2 == 0) { + begin = state - 1; + end = state + 1; + } else { + begin = state - 2; + end = state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + j = begin; + tmp_pair.high = lowest_transition.high; + tmp_pair.low = lowest_transition.low; + while (1) { + assert(j >= 1 && j <= 8); + transition.high = tmp_pair.high + transitions[j - 1].high; + transition.low = tmp_pair.low + transitions[j - 1].low; + if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) { + bcm43xx_lo_write(bcm, &transition); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + if (tmp < lowest_deviation) { + lowest_deviation = tmp; + state = j; + found_lower = 1; + + lowest_transition.high = transition.high; + lowest_transition.low = transition.low; + } + } + if (j == end) + break; + if (j == 8) + j = 1; + else + j++; + } + } while (i-- && found_lower); + + out_pair->high = lowest_transition.high; + out_pair->low = lowest_transition.low; +} + +/* Set the baseband attenuation value on chip. */ +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation) +{ + u16 value; + + if (bcm->current_core->phy->version == 0) { + value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); + value |= (baseband_attenuation & 0x000F); + bcm43xx_write16(bcm, 0x03E6, value); + return; + } + + if (bcm->current_core->phy->version > 1) { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; + value |= (baseband_attenuation << 2) & 0x003C; + } else { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078; + value |= (baseband_attenuation << 3) & 0x0078; + } + bcm43xx_phy_write(bcm, 0x0060, value); +} + +/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) +{ + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; + const int is_initializing = bcm43xx_is_initializing(bcm); + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 h, i, oldi = 0, j; + struct bcm43xx_lopair control; + struct bcm43xx_lopair *tmp_control; + u16 tmp; + u16 regstack[16] = { 0 }; + u8 oldchannel; + + //XXX: What are these? + u8 r27 = 0, r31; + + oldchannel = radio->channel; + /* Setup */ + if (phy->connected) { + regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + regstack[1] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + } + regstack[3] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000); + regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + regstack[5] = bcm43xx_phy_read(bcm, 0x15); + regstack[6] = bcm43xx_phy_read(bcm, 0x2A); + regstack[7] = bcm43xx_phy_read(bcm, 0x35); + regstack[8] = bcm43xx_phy_read(bcm, 0x60); + regstack[9] = bcm43xx_radio_read16(bcm, 0x43); + regstack[10] = bcm43xx_radio_read16(bcm, 0x7A); + regstack[11] = bcm43xx_radio_read16(bcm, 0x52); + if (phy->connected) { + regstack[12] = bcm43xx_phy_read(bcm, 0x0811); + regstack[13] = bcm43xx_phy_read(bcm, 0x0812); + regstack[14] = bcm43xx_phy_read(bcm, 0x0814); + regstack[15] = bcm43xx_phy_read(bcm, 0x0815); + } + bcm43xx_radio_selectchannel(bcm, 6, 0); + if (phy->connected) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + bcm43xx_dummy_transmission(bcm); + } + bcm43xx_radio_write16(bcm, 0x0043, 0x0006); + + bcm43xx_phy_set_baseband_attenuation(bcm, 2); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000); + bcm43xx_phy_write(bcm, 0x002E, 0x007F); + bcm43xx_phy_write(bcm, 0x080F, 0x0078); + bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7)); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); + bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + } + if (is_initializing) + bcm43xx_phy_lo_g_measure_txctl2(bcm); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + + /* Measure */ + control.low = 0; + control.high = 0; + for (h = 0; h < 10; h++) { + /* Loop over each possible RadioAttenuation (0-9) */ + i = pairorder[h]; + if (is_initializing) { + if (i == 3) { + control.low = 0; + control.high = 0; + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || + ((i % 2 == 0) && (oldi % 2 == 0))) { + tmp_control = bcm43xx_get_lopair(phy, oldi, 0); + memcpy(&control, tmp_control, sizeof(control)); + } else { + tmp_control = bcm43xx_get_lopair(phy, 3, 0); + memcpy(&control, tmp_control, sizeof(control)); + } + } + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp = i * 2 + j; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i); + bcm43xx_radio_write16(bcm, 0x52, + radio->txpower[3]); + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + oldi = i; + } + /* Loop over each possible RadioAttenuation (10-13) */ + for (i = 10; i < 14; i++) { + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + memcpy(&control, tmp_control, sizeof(control)); + tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i - 9); + bcm43xx_radio_write16(bcm, 0x52, + radio->txpower[3] + | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x7A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + } + + /* Restoration */ + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0015, 0xE300); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); + } else + bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); + bcm43xx_phy_lo_adjust(bcm, is_initializing); + bcm43xx_phy_write(bcm, 0x002E, 0x807F); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); + bcm43xx_phy_write(bcm, 0x0015, regstack[5]); + bcm43xx_phy_write(bcm, 0x002A, regstack[6]); + bcm43xx_phy_write(bcm, 0x0035, regstack[7]); + bcm43xx_phy_write(bcm, 0x0060, regstack[8]); + bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); + regstack[11] &= 0x00F0; + regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); + bcm43xx_radio_write16(bcm, 0x52, regstack[11]); + bcm43xx_write16(bcm, 0x03E2, regstack[3]); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, regstack[12]); + bcm43xx_phy_write(bcm, 0x0812, regstack[13]); + bcm43xx_phy_write(bcm, 0x0814, regstack[14]); + bcm43xx_phy_write(bcm, 0x0815, regstack[15]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); + bcm43xx_phy_write(bcm, 0x0802, regstack[1]); + } + bcm43xx_radio_selectchannel(bcm, oldchannel, 1); + +#ifdef CONFIG_BCM43XX_DEBUG + { + /* Sanity check for all lopairs. */ + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + tmp_control = phy->_lo_pairs + i; + if (tmp_control->low < -8 || tmp_control->low > 8 || + tmp_control->high < -8 || tmp_control->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", + tmp_control->low, tmp_control->high, i); + } + } + } +#endif /* CONFIG_BCM43XX_DEBUG */ +} + +static +void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) +{ + struct bcm43xx_lopair *pair; + + pair = bcm43xx_current_lopair(bcm); + pair->used = 1; +} + +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_lopair *pair; + int i; + + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + pair = phy->_lo_pairs + i; + pair->used = 0; + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s8 dbm = 0; + s32 tmp; + + tmp = phy->idle_tssi; + tmp += tssi; + tmp -= phy->savedpctlreg; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + tmp += 0x80; + tmp = limit_value(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + TODO(); //TODO: There's a FIXME on the specs + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + assert(0); + } + + return dbm; +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (phy->savedpctlreg == 0xFFFF) + return; + if ((bcm->board_type == 0x0416) && + (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: { + + TODO(); //TODO: Nothing for A PHYs yet :-/ + + break; + } + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: { + u16 tmp; + u16 txpower; + s8 v0, v1, v2, v3; + s8 average; + u8 max_pwr; + s16 desired_pwr, estimated_pwr, pwr_adjust; + s16 radio_att_delta, baseband_att_delta; + s16 radio_attenuation, baseband_attenuation; + unsigned long phylock_flags; + + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + bcm43xx_radio_clear_tssi(bcm); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) + average -= 13; + + estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); + + max_pwr = bcm->sprom.maxpower_bgphy; + + if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && + (phy->type == BCM43xx_PHYTYPE_G)) + max_pwr -= 0x3; + + /*TODO: + max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /*TODO: Get desired_pwr from wx_handlers or the stack + limit_value(desired_pwr, 0, max_pwr); + */ + + desired_pwr = max_pwr; /* remove this when we have a real desired_pwr */ + + pwr_adjust = desired_pwr - estimated_pwr; + + radio_att_delta = -(pwr_adjust + 7) >> 3; + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + bcm43xx_phy_lo_mark_current_used(bcm); + return; + } + + /* Calculate the new attenuation values. */ + baseband_attenuation = radio->txpower[0]; + baseband_attenuation += baseband_att_delta; + radio_attenuation = radio->txpower[1]; + radio_attenuation += radio_att_delta; + + /* Get baseband and radio attenuation values into their permitted ranges. + * baseband 0-11, radio 0-9. + * Radio attenuation affects power level 4 times as much as baseband. + */ + if (radio_attenuation < 0) { + baseband_attenuation -= (4 * -radio_attenuation); + radio_attenuation = 0; + } else if (radio_attenuation > 9) { + baseband_attenuation += (4 * (radio_attenuation - 9)); + radio_attenuation = 9; + } else { + while (baseband_attenuation < 0 && radio_attenuation > 0) { + baseband_attenuation += 4; + radio_attenuation--; + } + while (baseband_attenuation > 11 && radio_attenuation < 9) { + baseband_attenuation -= 4; + radio_attenuation++; + } + } + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + + txpower = radio->txpower[2]; + if ((radio->version == 0x2050) && (radio->revision == 2)) { + if (radio_attenuation <= 1) { + if (txpower == 0) { + txpower = 3; + radio_attenuation += 2; + baseband_attenuation += 2; + } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + baseband_attenuation += 4 * (radio_attenuation - 2); + radio_attenuation = 2; + } + } else if (radio_attenuation > 4 && txpower != 0) { + txpower = 0; + if (baseband_attenuation < 3) { + radio_attenuation -= 3; + baseband_attenuation += 2; + } else { + radio_attenuation -= 2; + baseband_attenuation -= 2; + } + } + } + radio->txpower[2] = txpower; + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + radio_attenuation = limit_value(radio_attenuation, 0, 9); + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, + radio_attenuation, txpower); + bcm43xx_phy_lo_mark_current_used(bcm); + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + break; + } + default: + assert(0); + } +} + +static inline +s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num/den; + else + return (num+den/2)/den; +} + +static inline +s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = bcm43xx_tssi2dbm_ad(f * 4096 - + bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + if (phy->type == BCM43xx_PHYTYPE_A) { + pab0 = (s16)(bcm->sprom.pa1b0); + pab1 = (s16)(bcm->sprom.pa1b1); + pab2 = (s16)(bcm->sprom.pa1b2); + } else { + pab0 = (s16)(bcm->sprom.pa0b0); + pab1 = (s16)(bcm->sprom.pa0b1); + pab2 = (s16)(bcm->sprom.pa0b2); + } + + if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) { + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == BCM43xx_PHYTYPE_A) { + if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_aphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy); + else + phy->idle_tssi = 62; + } else { + if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy); + else + phy->idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + printk(KERN_ERR PFX "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate " + "tssi2dBm table\n"); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + case BCM43xx_PHYTYPE_B: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + break; + case BCM43xx_PHYTYPE_G: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int bcm43xx_phy_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + int err = -ENODEV; + unsigned long flags; + + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + if (phy->rev == 2 || phy->rev == 3) { + bcm43xx_phy_inita(bcm); + err = 0; + } + break; + case BCM43xx_PHYTYPE_B: + switch (phy->rev) { + case 2: + bcm43xx_phy_initb2(bcm); + err = 0; + break; + case 4: + bcm43xx_phy_initb4(bcm); + err = 0; + break; + case 5: + bcm43xx_phy_initb5(bcm); + err = 0; + break; + case 6: + bcm43xx_phy_initb6(bcm); + err = 0; + break; + } + break; + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_initg(bcm); + err = 0; + break; + } + local_irq_restore(flags); + if (err) + printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); + + return err; +} + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 antennadiv; + u16 offset; + u16 value; + u32 ucodeflags; + + antennadiv = phy->antenna_diversity; + + if (antennadiv == 0xFFFF) + antennadiv = 3; + assert(antennadiv <= 3); + + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + if (phy->type == BCM43xx_PHYTYPE_A) + offset = 0x0000; + else + offset = 0x0400; + + if (antennadiv == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, offset + 1, + (bcm43xx_phy_read(bcm, offset + 1) + & 0x7E7F) | value); + + if (antennadiv >= 2) { + if (antennadiv == 2) + value = (antennadiv << 7); + else + value = (0/*force0*/ << 7); + bcm43xx_phy_write(bcm, offset + 0x2B, + (bcm43xx_phy_read(bcm, offset + 0x2B) + & 0xFEFF) | value); + } + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (antennadiv >= 2) + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + | 0x2000); + else + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + & ~0x2000); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0461, + bcm43xx_phy_read(bcm, 0x0461) + | 0x0010); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x0015); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0427, 0x0008); + else + bcm43xx_phy_write(bcm, 0x0427, + (bcm43xx_phy_read(bcm, 0x0427) + & 0x00FF) | 0x0008); + } + else if (phy->rev >= 6) + bcm43xx_phy_write(bcm, 0x049B, 0x00DC); + } else { + if (phy->rev < 3) + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0x00FF) | 0x0024); + else { + bcm43xx_phy_write(bcm, 0x0061, + bcm43xx_phy_read(bcm, 0x0061) + | 0x0010); + if (phy->rev == 3) { + bcm43xx_phy_write(bcm, 0x0093, 0x001D); + bcm43xx_phy_write(bcm, 0x0027, 0x0008); + } else { + bcm43xx_phy_write(bcm, 0x0093, 0x003A); + bcm43xx_phy_write(bcm, 0x0027, + (bcm43xx_phy_read(bcm, 0x0027) + & 0x00FF) | 0x0008); + } + } + } + break; + case BCM43xx_PHYTYPE_B: + if (bcm->current_core->rev == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, 0x03E2, + (bcm43xx_phy_read(bcm, 0x03E2) + & 0xFE7F) | value); + break; + default: + assert(0); + } + + if (antennadiv >= 2) { + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags | BCM43xx_UCODEFLAG_AUTODIV); + } + + phy->antenna_diversity = antennadiv; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h new file mode 100644 index 00000000000..1f321ef42be --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h @@ -0,0 +1,74 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_PHY_H_ +#define BCM43xx_PHY_H_ + +#include + +struct bcm43xx_private; + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_lock(bcm, flags) \ + do { \ + local_irq_save(flags); \ + bcm43xx_raw_phy_lock(bcm); \ + } while (0) +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_unlock(bcm, flags) \ + do { \ + bcm43xx_raw_phy_unlock(bcm); \ + local_irq_restore(flags); \ + } while (0) + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); + +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm); +int bcm43xx_phy_init(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm); +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm); +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect); + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm); + +/* Adjust the LocalOscillator to the saved values. + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. + */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed); +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation); + +#endif /* BCM43xx_PHY_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c new file mode 100644 index 00000000000..9a55e9d0052 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -0,0 +1,592 @@ +/* + + Broadcom BCM43xx wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_main.h" + +#include + + +static inline +u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, + u16 offset) +{ + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); +} + +static inline +void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, + u16 offset, u16 value) +{ + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); +} + +static inline +void tx_start(struct bcm43xx_pioqueue *queue) +{ + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT); +} + +static inline +void tx_octet(struct bcm43xx_pioqueue *queue, + u8 octet) +{ + if (queue->bcm->current_core->rev < 3) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + } +} + +static inline +void tx_data(struct bcm43xx_pioqueue *queue, + u8 *packet, + unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->bcm->current_core->rev < 3) { + data = be16_to_cpu( *((u16 *)packet) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + i += 2; + } + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI); + for ( ; i < octets - 1; i += 2) { + data = be16_to_cpu( *((u16 *)(packet + i)) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, packet[octets - 1]); +} + +static inline +void tx_complete(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb) +{ + u16 data; + + if (queue->bcm->current_core->rev < 3) { + data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE); + } +} + +static inline +u16 generate_cookie(struct bcm43xx_pioqueue *queue, + int packetindex) +{ + u16 cookie = 0x0000; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + default: + assert(0); + case BCM43xx_MMIO_PIO1_BASE: + break; + case BCM43xx_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + } + assert(((u16)packetindex & 0xF000) == 0x0000); + cookie |= (u16)packetindex; + + return cookie; +} + +static inline +struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, + struct bcm43xx_pio_txpacket **packet) +{ + struct bcm43xx_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = bcm->current_core->pio->queue0; + break; + case 0x1000: + queue = bcm->current_core->pio->queue1; + break; + case 0x2000: + queue = bcm->current_core->pio->queue2; + break; + case 0x3000: + queue = bcm->current_core->pio->queue3; + break; + default: + assert(0); + } + + packetindex = (cookie & 0x0FFF); + assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); + *packet = queue->__tx_packets_cache + packetindex; + + return queue; +} + +static inline +void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb, + struct bcm43xx_pio_txpacket *packet) +{ + unsigned int octets; + + assert(skb_shinfo(skb)->nr_frags == 0); + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); + + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); + bcm43xx_generate_txhdr(queue->bcm, + (struct bcm43xx_txhdr *)skb->data, + skb->data + sizeof(struct bcm43xx_txhdr), + skb->len - sizeof(struct bcm43xx_txhdr), + (packet->xmitted_frags == 0), + generate_cookie(queue, pio_txpacket_getindex(packet))); + + tx_start(queue); + octets = skb->len; + if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue. + octets -= 2; + tx_data(queue, (u8 *)skb->data, octets); + tx_complete(queue, skb); +} + +static inline +int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + struct ieee80211_txb *txb = packet->txb; + struct sk_buff *skb; + u16 octets; + int i; + + for (i = packet->xmitted_frags; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + + octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); + + assert(queue->tx_devq_size >= octets); + assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); + assert(queue->tx_devq_used <= queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX-work-handler + * retry later. + */ + if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + assert(packet->xmitted_frags <= packet->txb->nr_frags); + packet->xmitted_frags++; + packet->xmitted_octets += octets; + } + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void free_txpacket(struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + + ieee80211_txb_free(packet->txb); + + list_move(&packet->list, &packet->queue->txfree); + + assert(queue->tx_devq_used >= packet->xmitted_octets); + queue->tx_devq_used -= packet->xmitted_octets; + assert(queue->tx_devq_packets >= packet->xmitted_frags); + queue->tx_devq_packets -= packet->xmitted_frags; +} + +static void txwork_handler(void *d) +{ + struct bcm43xx_pioqueue *queue = d; + unsigned long flags; + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + int err; + + spin_lock_irqsave(&queue->txlock, flags); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + assert(packet->xmitted_frags < packet->txb->nr_frags); + if (packet->xmitted_frags == 0) { + int i; + struct sk_buff *skb; + + /* Check if the device queue is big + * enough for every fragment. If not, drop the + * whole packet. + */ + for (i = 0; i < packet->txb->nr_frags; i++) { + skb = packet->txb->fragments[i]; + if (unlikely(skb->len > queue->tx_devq_size)) { + dprintkl(KERN_ERR PFX "PIO TX device queue too small. " + "Dropping packet...\n"); + free_txpacket(packet); + goto next_packet; + } + } + } + /* Now try to transmit the packet. + * This may not completely succeed. + */ + err = pio_tx_packet(packet); + if (err) + break; +next_packet: + continue; + } + spin_unlock_irqrestore(&queue->txlock, flags); +} + +static void setup_txqueues(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet; + int i; + + for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { + packet = queue->__tx_packets_cache + i; + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, + u16 pio_mmio_base) +{ + struct bcm43xx_pioqueue *queue; + u32 value; + u16 qsize; + + queue = kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + memset(queue, 0, sizeof(*queue)); + + queue->bcm = bcm; + queue->mmio_base = pio_mmio_base; + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + spin_lock_init(&queue->txlock); + INIT_WORK(&queue->txwork, txwork_handler, queue); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value |= BCM43xx_SBF_XFER_REG_BYTESWAP; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + + qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); + if (qsize <= BCM43xx_PIO_TXQADJUST) { + printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize); + goto err_freequeue; + } + qsize -= BCM43xx_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + +out: + return queue; + +err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + + netif_tx_disable(queue->bcm->net_dev); + assert(queue->bcm->shutting_down); + cancel_delayed_work(&queue->txwork); + flush_workqueue(queue->bcm->workqueue); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet); +} + +static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3); + bcm->current_core->pio->queue3 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); + bcm->current_core->pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); + bcm->current_core->pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); + bcm->current_core->pio->queue0 = NULL; +} + +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_pioqueue *queue; + int err = -ENOMEM; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); + if (!queue) + goto out; + bcm->current_core->pio->queue0 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + bcm->current_core->pio->queue1 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + bcm->current_core->pio->queue2 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + bcm->current_core->pio->queue3 = queue; + + if (bcm->current_core->rev < 3) + bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; + + dprintk(KERN_INFO PFX "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy2: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); + bcm->current_core->pio->queue2 = NULL; +err_destroy1: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); + bcm->current_core->pio->queue1 = NULL; +err_destroy0: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); + bcm->current_core->pio->queue0 = NULL; + goto out; +} + +static inline +int pio_transfer_txb(struct bcm43xx_pioqueue *queue, + struct ieee80211_txb *txb) +{ + struct bcm43xx_pio_txpacket *packet; + unsigned long flags; + u16 tmp; + + spin_lock_irqsave(&queue->txlock, flags); + assert(!queue->tx_suspended); + assert(!list_empty(&queue->txfree)); + + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) { + spin_unlock_irqrestore(&queue->txlock, flags); + return -EBUSY; + } + + packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); + + packet->txb = txb; + list_move_tail(&packet->list, &queue->txqueue); + packet->xmitted_octets = 0; + packet->xmitted_frags = 0; + + /* Suspend TX, if we are out of packets in the "free" queue. */ + if (unlikely(list_empty(&queue->txfree))) { + netif_stop_queue(queue->bcm->net_dev); + queue->tx_suspended = 1; + } + + spin_unlock_irqrestore(&queue->txlock, flags); + queue_work(queue->bcm->workqueue, &queue->txwork); + + return 0; +} + +int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return pio_transfer_txb(bcm->current_core->pio->queue1, txb); +} + +void fastcall +bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_pioqueue *queue; + struct bcm43xx_pio_txpacket *packet; + unsigned long flags; + + queue = parse_cookie(bcm, status->cookie, &packet); + assert(queue); + spin_lock_irqsave(&queue->txlock, flags); + free_txpacket(packet); + if (unlikely(queue->tx_suspended)) { + queue->tx_suspended = 0; + netif_wake_queue(queue->bcm->net_dev); + } + + /* If there are packets on the txqueue, + * start the work handler again. + */ + if (!list_empty(&queue->txqueue)) { + queue_work(queue->bcm->workqueue, + &queue->txwork); + } + spin_unlock_irqrestore(&queue->txlock, flags); +} + +static void pio_rx_error(struct bcm43xx_pioqueue *queue, + const char *error) +{ + printk("PIO RX error: %s\n", error); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); +} + +void fastcall +bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ + u16 preamble[21] = { 0 }; + struct bcm43xx_rxhdr *rxhdr; + u16 tmp; + u16 len; + int i, err; + int preamble_readwords; + struct sk_buff *skb; + + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { + dprintkl(KERN_ERR PFX "PIO RX: No data available\n"); + return; + } + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (tmp & BCM43xx_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + dprintkl(KERN_ERR PFX "PIO RX timed out\n"); + return; +data_ready: + + len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { + pio_rx_error(queue, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + preamble[i + 1] = cpu_to_be16(tmp); + } + rxhdr = (struct bcm43xx_rxhdr *)preamble; + if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { + pio_rx_error(queue, "invalid frame"); + if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) { + for (i = 0; i < 15; i++) + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */ + } + return; + } +//FIXME +#if 0 + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { + bcm43xx_rx_transmitstatus(queue->bcm, + (const struct bcm43xx_hwxmitstatus *)(preamble + 1)); + return; + } +#endif + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, "out of memory"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + *((u16 *)(skb->data + i)) = tmp; + } + if (len % 2) { + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + skb->data[len - 1] = (tmp & 0x00FF); + skb->data[0] = (tmp & 0xFF00) >> 8; + } + err = bcm43xx_rx(queue->bcm, skb, rxhdr); + if (unlikely(err)) + dev_kfree_skb_irq(skb); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h new file mode 100644 index 00000000000..71b92ee3416 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h @@ -0,0 +1,88 @@ +#ifndef BCM43xx_PIO_H_ +#define BCM43xx_PIO_H_ + +#include "bcm43xx.h" + +#include +#include +#include +#include + + +#define BCM43xx_PIO_TXCTL 0x00 +#define BCM43xx_PIO_TXDATA 0x02 +#define BCM43xx_PIO_TXQBUFSIZE 0x04 +#define BCM43xx_PIO_RXCTL 0x08 +#define BCM43xx_PIO_RXDATA 0x0A + +#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0) +#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1) +#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2) +#define BCM43xx_PIO_TXCTL_INIT (1 << 3) +#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7) + +#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define BCM43xx_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define BCM43xx_PIO_MAXTXDEVQPACKETS 31 +#define BCM43xx_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define BCM43xx_PIO_MAXTXPACKETS 256 + + +struct bcm43xx_pioqueue; +struct bcm43xx_xmitstatus; + +struct bcm43xx_pio_txpacket { + struct bcm43xx_pioqueue *queue; + struct ieee80211_txb *txb; + struct list_head list; + + u8 xmitted_frags; + u16 xmitted_octets; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) + +struct bcm43xx_pioqueue { + struct bcm43xx_private *bcm; + u16 mmio_base; + + u8 tx_suspended:1; + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Locking of the TX queues and the accounting. */ + spinlock_t txlock; + struct work_struct txwork; + struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; +}; + +int bcm43xx_pio_init(struct bcm43xx_private *bcm); +void bcm43xx_pio_free(struct bcm43xx_private *bcm); + +int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb)); +void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status)); + +void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)); +#endif /* BCM43xx_PIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c new file mode 100644 index 00000000000..3c92b62807c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c @@ -0,0 +1,358 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_power.h" +#include "bcm43xx_main.h" + + +/* Get max/min slowclock frequency + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, + int get_max) +{ + int limit = 0; + int divisor; + int selection; + int err; + u32 tmp; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err) + goto out; + + if (bcm->current_core->rev < 6) { + if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || + (bcm->bustype == BCM43xx_BUSTYPE_SB)) { + selection = 1; + divisor = 32; + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); + if (err) { + printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); + goto out_switchback; + } + if (tmp & 0x10) { + /* PCI */ + selection = 2; + divisor = 64; + } else { + /* XTAL */ + selection = 1; + divisor = 32; + } + } + } else if (bcm->current_core->rev < 10) { + selection = (tmp & 0x07); + if (selection) { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + } else + divisor = 1; + } else { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + selection = 1; + } + + switch (selection) { + case 0: + /* LPO */ + if (get_max) + limit = 43000; + else + limit = 25000; + break; + case 1: + /* XTAL */ + if (get_max) + limit = 20200000; + else + limit = 19800000; + break; + case 2: + /* PCI */ + if (get_max) + limit = 34000000; + else + limit = 25000000; + break; + default: + assert(0); + } + limit /= divisor; + +out_switchback: + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return limit; +} + +/* init power control + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_init(struct bcm43xx_private *bcm) +{ + int err, maxfreq; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + return 0; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) +{ + u16 delay = 0; + int err; + u32 pll_on_delay; + struct bcm43xx_coreinfo *old_core; + int minfreq; + + if (bcm->bustype != BCM43xx_BUSTYPE_PCI) + goto out; + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + goto out; + + minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); + pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); + delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return delay; +} + +/* set the powercontrol clock + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) +{ + int err; + struct bcm43xx_coreinfo *old_core; + u32 tmp; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + if (bcm->core_chipcommon.rev < 6) { + if (mode == BCM43xx_PCTL_CLK_FAST) { + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + } + } else { + if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && + (bcm->core_chipcommon.rev < 10)) { + switch (mode) { + case BCM43xx_PCTL_CLK_FAST: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_SLOW: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp |= BCM43xx_PCTL_FORCE_SLOW; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_DYNAMIC: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp &= ~BCM43xx_PCTL_FORCE_SLOW; + tmp |= BCM43xx_PCTL_FORCE_PLL; + tmp &= ~BCM43xx_PCTL_DYN_XTAL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + } + } + } + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) +{ + int err; + u32 in, out, outenable; + + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); + if (err) + goto err_pci; + + outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + if (on) { + if (in & 0x40) + return 0; + + out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + udelay(1000); + + out &= ~BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + udelay(5000); + } else { + if (bcm->current_core->rev < 5) + return 0; + if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) + return 0; + +/* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? + * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); + * if (err) + * return err; + * if (((bcm->current_core->rev >= 3) && + * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || + * ((bcm->current_core->rev < 3) && + * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) + * return 0; + * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + * if (err) + * return err; + */ + + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + if (err) + goto out; + out &= ~BCM43xx_PCTL_XTAL_POWERUP; + out |= BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + } + +out: + return err; + +err_pci: + printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); + err = -EBUSY; + goto out; +} + +/* Set the PowerSavingControlBits. + * Bitvalues: + * 0 => unset the bit + * 1 => set the bit + * -1 => calculate the bit + */ +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26) +{ + int i; + u32 status; + +//FIXME: Force 25 to off and 26 to on for now: +bit25 = 0; +bit26 = 1; + + if (bit25 == -1) { + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc + // and thus is not an AP and we are associated, set bit 25 + } + if (bit26 == -1) { + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, + // or we are associated, or FIXME, or the latest PS-Poll packet sent was + // successful, set bit26 + } + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (bit25) + status |= BCM43xx_SBF_PS1; + else + status &= ~BCM43xx_SBF_PS1; + if (bit26) + status |= BCM43xx_SBF_PS2; + else + status &= ~BCM43xx_SBF_PS2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + if (bit26 && bcm->current_core->rev >= 5) { + for (i = 0; i < 100; i++) { + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) + break; + udelay(10); + } + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h new file mode 100644 index 00000000000..5f63640810b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h @@ -0,0 +1,47 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_POWER_H_ +#define BCM43xx_POWER_H_ + +#include + + +struct bcm43xx_private; + +int bcm43xx_pctl_init(struct bcm43xx_private *bcm); +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode); +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on); +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm); + +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26); + +#endif /* BCM43xx_POWER_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c new file mode 100644 index 00000000000..1e65658552b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -0,0 +1,1766 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" + + +/* Table for bcm43xx_radio_calibrationvalue() */ +static const u16 rcc_table[16] = { + 0x0002, 0x0003, 0x0001, 0x000F, + 0x0006, 0x0007, 0x0005, 0x000F, + 0x000A, 0x000B, 0x0009, 0x000F, + 0x000E, 0x000F, 0x000D, 0x000F, +}; + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + assert((value & ~0x000F) == 0x0000); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_bg(u8 channel) +{ + /* Frequencies are given as frequencies_bg[index] + 2.4GHz + * Starting with channel 1 + */ + static const u16 frequencies_bg[14] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, + }; + + assert(channel >= 1 && channel <= 14); + + return frequencies_bg[channel - 1]; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_a(u8 channel) +{ + assert(channel <= 200); + + return (5000 + 5 * channel); +} + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + udelay(10); +} + +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */ + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); +} + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + offset |= 0x0040; + break; + case BCM43xx_PHYTYPE_B: + if (radio->version == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (radio->version == 0x2050) { + offset |= 0x80; + } else + assert(0); + break; + case BCM43xx_PHYTYPE_G: + offset |= 0x80; + break; + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); +} + +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); +} + +static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, + s16 first, s16 second, s16 third) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 offset = 0x0400; + u16 tmp; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x10; + end = 0x20; + } + + for (i = 0; i < 4; i++) + bcm43xx_ilt_write16(bcm, offset + i, first); + + for (i = start; i < end; i++) + bcm43xx_ilt_write16(bcm, offset + i, second); + + if (third != -1) { + tmp = ((u16)third << 14) | ((u16)third << 6); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp); + } + bcm43xx_dummy_transmission(bcm); +} + +static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i, tmp; + u16 offset = 0x0400; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x0010; + end = 0x0020; + } + + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + bcm43xx_ilt_write16(bcm, offset + i, tmp); + } + + for (i = start; i < end; i++) + bcm43xx_ilt_write16(bcm, offset + i, i - start); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000); + bcm43xx_dummy_transmission(bcm); +} + +/* Synthetic PU workaround */ +static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + if (radio->version != 0x2050 || radio->revision >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(1)); + } + udelay(100); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); +} + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = bcm43xx_phy_read(bcm, 0x0403); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5); + if (radio->aci_hw_rssi) + rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0;i < 100; i++) { + temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + bcm43xx_phy_write(bcm, 0x0403, saved); + + return ret; +} + +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u8 ret[13]; + unsigned int channel = radio->channel; + unsigned int i, j, start, end; + unsigned long phylock_flags; + + if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_set_all_gains(bcm, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i-1] = bcm43xx_radio_aci_detect(bcm, i); + } + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003); + bcm43xx_phy_write(bcm, 0x0403, + bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); + bcm43xx_set_original_gains(bcm); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) +{ + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset) +{ + u16 val; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA); + + return (s16)val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = bcm43xx_nrssi_hw_read(bcm, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + bcm43xx_nrssi_hw_write(bcm, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) +{ + s16 i, delta; + s32 tmp; + + delta = 0x1F - bcm->current_core->radio->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * bcm->current_core->radio->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + bcm->current_core->radio->nrssi_lt[i] = tmp; + } +} + +static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = bcm43xx_phy_read(bcm, 0x0001); + backup[1] = bcm43xx_phy_read(bcm, 0x0811); + backup[2] = bcm43xx_phy_read(bcm, 0x0812); + backup[3] = bcm43xx_phy_read(bcm, 0x0814); + backup[4] = bcm43xx_phy_read(bcm, 0x0815); + backup[5] = bcm43xx_phy_read(bcm, 0x005A); + backup[6] = bcm43xx_phy_read(bcm, 0x0059); + backup[7] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_phy_read(bcm, 0x000A); + backup[9] = bcm43xx_phy_read(bcm, 0x0003); + backup[10] = bcm43xx_radio_read16(bcm, 0x007A); + backup[11] = bcm43xx_radio_read16(bcm, 0x0043); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0001, + (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = bcm43xx_phy_read(bcm, 0x002E); + backup[13] = bcm43xx_phy_read(bcm, 0x002F); + backup[14] = bcm43xx_phy_read(bcm, 0x080F); + backup[15] = bcm43xx_phy_read(bcm, 0x0810); + backup[16] = bcm43xx_phy_read(bcm, 0x0801); + backup[17] = bcm43xx_phy_read(bcm, 0x0060); + backup[18] = bcm43xx_phy_read(bcm, 0x0014); + backup[19] = bcm43xx_phy_read(bcm, 0x0478); + + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, 0x002F, 0); + bcm43xx_phy_write(bcm, 0x080F, 0); + bcm43xx_phy_write(bcm, 0x0810, 0); + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) | 0x0040); + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x0030); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->rev == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) + | 0x0040); + bcm43xx_phy_write(bcm, 0x007A, + bcm43xx_phy_read(bcm, 0x007A) | 0x000F); + bcm43xx_set_all_gains(bcm, 3, 0, 1); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + bcm43xx_radio_write16(bcm, 0x007B, saved); + + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x002E, backup[12]); + bcm43xx_phy_write(bcm, 0x002F, backup[13]); + bcm43xx_phy_write(bcm, 0x080F, backup[14]); + bcm43xx_phy_write(bcm, 0x0810, backup[15]); + } + bcm43xx_phy_write(bcm, 0x0814, backup[3]); + bcm43xx_phy_write(bcm, 0x0815, backup[4]); + bcm43xx_phy_write(bcm, 0x005A, backup[5]); + bcm43xx_phy_write(bcm, 0x0059, backup[6]); + bcm43xx_phy_write(bcm, 0x0058, backup[7]); + bcm43xx_phy_write(bcm, 0x000A, backup[8]); + bcm43xx_phy_write(bcm, 0x0003, backup[9]); + bcm43xx_radio_write16(bcm, 0x0043, backup[11]); + bcm43xx_radio_write16(bcm, 0x007A, backup[10]); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2); + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) | 0x8000); + bcm43xx_set_original_gains(bcm); + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x0801, backup[16]); + bcm43xx_phy_write(bcm, 0x0060, backup[17]); + bcm43xx_phy_write(bcm, 0x0014, backup[18]); + bcm43xx_phy_write(bcm, 0x0478, backup[19]); + } + bcm43xx_phy_write(bcm, 0x0001, backup[0]); + bcm43xx_phy_write(bcm, 0x0812, backup[2]); + bcm43xx_phy_write(bcm, 0x0811, backup[1]); +} + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0030); + backup[4] = bcm43xx_phy_read(bcm, 0x0026); + backup[5] = bcm43xx_phy_read(bcm, 0x0015); + backup[6] = bcm43xx_phy_read(bcm, 0x002A); + backup[7] = bcm43xx_phy_read(bcm, 0x0020); + backup[8] = bcm43xx_phy_read(bcm, 0x005A); + backup[9] = bcm43xx_phy_read(bcm, 0x0059); + backup[10] = bcm43xx_phy_read(bcm, 0x0058); + backup[11] = bcm43xx_read16(bcm, 0x03E2); + backup[12] = bcm43xx_read16(bcm, 0x03E6); + backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + tmp = bcm43xx_radio_read16(bcm, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x7F7F); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0015, + bcm43xx_phy_read(bcm, 0x0015) | 0x0020); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + + nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_write16(bcm, 0x03E6, 0x0040); + } else if (phy->rev == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000); + } + bcm43xx_phy_write(bcm, 0x0020, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + bcm43xx_radio_write16(bcm, 0x005A, 0x0060); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_phy_write(bcm, 0x0030, backup[3]); + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_write16(bcm, 0x03E2, backup[11]); + bcm43xx_phy_write(bcm, 0x0026, backup[4]); + bcm43xx_phy_write(bcm, 0x0015, backup[5]); + bcm43xx_phy_write(bcm, 0x002A, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + if (phy->rev != 0) + bcm43xx_write16(bcm, 0x03F4, backup[13]); + + bcm43xx_phy_write(bcm, 0x0020, backup[7]); + bcm43xx_phy_write(bcm, 0x005A, backup[8]); + bcm43xx_phy_write(bcm, 0x0059, backup[9]); + bcm43xx_phy_write(bcm, 0x0058, backup[10]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + radio->nrssi[0] = nrssi0; + radio->nrssi[1] = nrssi1; + } + break; + case BCM43xx_PHYTYPE_G: +//FIXME: Something is broken here. This is called when enabling WLAN interfmode. +// If this is done at runtime, I get an XMIT ERROR and transmission is +// broken. I guess some important register is overwritten by accident. +// The XMIT ERROR comes from the dummy_transmissions in set_gains. + if (radio->revision >= 9) + return; + if (radio->revision == 8) + bcm43xx_calc_nrssi_offset(bcm); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + backup[7] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, + bcm43xx_read16(bcm, 0x03E2) | 0x8000); + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0015); + backup[4] = bcm43xx_phy_read(bcm, 0x005A); + backup[5] = bcm43xx_phy_read(bcm, 0x0059); + backup[6] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_read16(bcm, 0x03E6); + backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = bcm43xx_phy_read(bcm, 0x002E); + backup[11] = bcm43xx_phy_read(bcm, 0x002F); + backup[12] = bcm43xx_phy_read(bcm, 0x080F); + backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL); + backup[14] = bcm43xx_phy_read(bcm, 0x0801); + backup[15] = bcm43xx_phy_read(bcm, 0x0060); + backup[16] = bcm43xx_phy_read(bcm, 0x0014); + backup[17] = bcm43xx_phy_read(bcm, 0x0478); + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: case 6: case 7: + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) + | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + | 0x0040); + break; + case 3: case 5: + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + & 0xFFBF); + break; + } + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) + | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) + | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_set_all_gains(bcm, 0, 8, 0); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | 0x2000); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020); + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020); + } + + bcm43xx_set_all_gains(bcm, 3, 0, 1); + if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x001F); + } else { + tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F; + bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060); + tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0; + bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009); + } + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + radio->nrssi[0] = nrssi1; + radio->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x002E, backup[10]); + bcm43xx_phy_write(bcm, 0x002F, backup[11]); + bcm43xx_phy_write(bcm, 0x080F, backup[12]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF); + } + + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + bcm43xx_write16(bcm, 0x03E2, backup[7]); + bcm43xx_write16(bcm, 0x03E6, backup[8]); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]); + bcm43xx_phy_write(bcm, 0x0015, backup[3]); + bcm43xx_phy_write(bcm, 0x005A, backup[4]); + bcm43xx_phy_write(bcm, 0x0059, backup[5]); + bcm43xx_phy_write(bcm, 0x0058, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); + bcm43xx_set_original_gains(bcm); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x8000); + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x0801, backup[14]); + bcm43xx_phy_write(bcm, 0x0060, backup[15]); + bcm43xx_phy_write(bcm, 0x0014, backup[16]); + bcm43xx_phy_write(bcm, 0x0478, backup[17]); + } + bcm43xx_nrssi_mem_update(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + break; + default: + assert(0); + } +} + +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + s16 threshold; + s32 a, b; + int tmp; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: { + int radiotype = 0; + + if (phy->rev < 2) + return; + if (radio->version != 0x2050) + return; + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) + return; + + tmp = radio->revision; + if ((radio->manufact == 0x175 && tmp == 5) || + (radio->manufact == 0x17F && (tmp == 3 || tmp == 4))) + radiotype = 1; + + if (radiotype == 1) { + threshold = bcm->current_core->radio->nrssi[1] - 5; + } else { + threshold = 40 * radio->nrssi[0]; + threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); + threshold += 20; + threshold /= 10; + } + threshold = limit_value(threshold, 0, 0x3E); + bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); + + if (radiotype == 1) { + bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); + bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); + bcm43xx_phy_write(bcm, 0x0085, 0x0A09); + bcm43xx_phy_write(bcm, 0x0084, 0x0808); + bcm43xx_phy_write(bcm, 0x0083, 0x0808); + bcm43xx_phy_write(bcm, 0x0082, 0x0604); + bcm43xx_phy_write(bcm, 0x0081, 0x0302); + bcm43xx_phy_write(bcm, 0x0080, 0x0100); + } + break; + } + case BCM43xx_PHYTYPE_G: + if (!phy->connected || + !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x09EB); + } else { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + tmp = radio->interfmode; + if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + a = -13; + b = -17; + } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE && + !radio->aci_enable) { + a = -13; + b = -10; + } else { + a = -8; + b = -9; + } + a += 0x1B; + a *= radio->nrssi[1] - radio->nrssi[0]; + a += radio->nrssi[0] * 0x40; + a /= 64; + b += 0x1B; + b *= radio->nrssi[1] - radio->nrssi[0]; + b += radio->nrssi[0] * 0x40; + b /= 64; + + a = limit_value(a, -31, 31); + b = limit_value(b, -31, 31); + + tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; + tmp_u16 |= ((u32)a & 0x003F); + tmp_u16 |= (((u32)b & 0x003F) << 6); + bcm43xx_phy_write(bcm, 0x048A, tmp_u16); + } + break; + default: + assert(0); + } +} + +/* Helper macros to save on and restore values from the radio->interfstack */ +#ifdef stack_save +# undef stack_save +#endif +#ifdef stack_restore +# undef stack_restore +#endif +#define stack_save(value) \ + do { \ + assert(i < ARRAY_SIZE(radio->interfstack)); \ + stack[i++] = (value); \ + } while (0) + +#define stack_restore() \ + ({ \ + assert(i < ARRAY_SIZE(radio->interfstack)); \ + stack[i++]; \ + }) + +static void +bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int i = 0; + u16 *stack = radio->interfstack; + u16 tmp, flipped; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); + break; + } + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if ((flipped >> 1) >= 4) + tmp = flipped - 3; + tmp = flip_4bit(tmp); + bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + + bcm43xx_calc_nrssi_threshold(bcm); + + if (bcm->current_core->rev < 5) { + stack_save(bcm43xx_phy_read(bcm, 0x0406)); + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); + } else { + stack_save(bcm43xx_phy_read(bcm, 0x04C0)); + stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + bcm43xx_phy_write(bcm, 0x04C0, 0x3E04); + bcm43xx_phy_write(bcm, 0x04C1, 0x0640); + } + + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); + + stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); + stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); + stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); + stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403); + stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504); + + stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + bcm43xx_phy_write(bcm, 0x04A7, 0x0002); + stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); + stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); + stack_save(bcm43xx_phy_read(bcm, 0x0493)); + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); + stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); + stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800) + break; + + radio->aci_enable = 1; + + stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)); + stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)); + if (bcm->current_core->rev < 5) { + stack_save(bcm43xx_phy_read(bcm, 0x0406)); + } else { + stack_save(bcm43xx_phy_read(bcm, 0x04C0)); + stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + } + stack_save(bcm43xx_phy_read(bcm, 0x0033)); + stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + stack_save(bcm43xx_phy_read(bcm, 0x0493)); + stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + stack_save(bcm43xx_phy_read(bcm, 0x048A)); + stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002); + + bcm43xx_phy_write(bcm, 0x04A7, 0x0800); + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A); + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, 0x280D); + } else { + bcm43xx_phy_write(bcm, 0x04C0, 0x0640); + bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); + } + + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006); + + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +static void +bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int i = 0; + u16 *stack = radio->interfstack; + u16 tmp, flipped; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + break; + } + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if ((flipped >> 1) >= 0x000C) + tmp = flipped + 3; + tmp = flip_4bit(tmp); + bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + + bcm43xx_calc_nrssi_threshold(bcm); + + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, stack_restore()); + } else { + bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + } + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + + if (!bcm->bad_frames_preempt) + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); + bcm43xx_phy_write(bcm, 0x0493, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800) + break; + + radio->aci_enable = 0; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore()); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore()); + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, stack_restore()); + } else { + bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + } + bcm43xx_phy_write(bcm, 0x0033, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + bcm43xx_phy_write(bcm, 0x0493, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); + + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +#undef stack_save +#undef stack_restore + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int currentmode; + + if ((phy->type != BCM43xx_PHYTYPE_G) || + (phy->rev == 0) || + (!phy->connected)) + return -ENODEV; + + radio->aci_wlan_automatic = 0; + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_AUTOWLAN: + radio->aci_wlan_automatic = 1; + if (radio->aci_enable) + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + else + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case BCM43xx_RADIO_INTERFMODE_NONE: + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = radio->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE) + bcm43xx_radio_interference_mitigation_disable(bcm, currentmode); + + if (mode == BCM43xx_RADIO_INTERFMODE_NONE) { + radio->aci_enable = 0; + radio->aci_hw_rssi = 0; + } else + bcm43xx_radio_interference_mitigation_enable(bcm, mode); + radio->interfmode = mode; + + return 0; +} + +static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) +{ + u16 reg, index, ret; + + reg = bcm43xx_radio_read16(bcm, 0x0060); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 backup[19] = { 0 }; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + backup[0] = bcm43xx_radio_read16(bcm, 0x0043); + backup[14] = bcm43xx_radio_read16(bcm, 0x0051); + backup[15] = bcm43xx_radio_read16(bcm, 0x0052); + backup[1] = bcm43xx_phy_read(bcm, 0x0015); + backup[16] = bcm43xx_phy_read(bcm, 0x005A); + backup[17] = bcm43xx_phy_read(bcm, 0x0059); + backup[18] = bcm43xx_phy_read(bcm, 0x0058); + if (phy->type == BCM43xx_PHYTYPE_B) { + backup[2] = bcm43xx_phy_read(bcm, 0x0030); + backup[3] = bcm43xx_read16(bcm, 0x03EC); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + } else { + if (phy->connected) { + backup[4] = bcm43xx_phy_read(bcm, 0x0811); + backup[5] = bcm43xx_phy_read(bcm, 0x0812); + backup[6] = bcm43xx_phy_read(bcm, 0x0814); + backup[7] = bcm43xx_phy_read(bcm, 0x0815); + backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + backup[9] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, 0x0814, + (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); + bcm43xx_phy_write(bcm, 0x0815, + (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); + } + backup[10] = bcm43xx_phy_read(bcm, 0x0035); + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); + backup[11] = bcm43xx_read16(bcm, 0x03E6); + backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + // Initialization + if (phy->version == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + if (phy->version >= 2) + bcm43xx_write16(bcm, 0x03E6, 0x0040); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); + } + + ret = bcm43xx_radio_calibrationvalue(bcm); + + if (phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_radio_write16(bcm, 0x0078, 0x0003); + + bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); + bcm43xx_phy_write(bcm, 0x002B, 0x1403); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); + bcm43xx_radio_write16(bcm, 0x0051, + (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) | 0x0009); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp1 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + + tmp1++; + tmp1 >>= 9; + udelay(10); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020); + backup[13] = bcm43xx_radio_read16(bcm, 0x0078); + udelay(10); + for (j = 0; j < 16; j++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0D80); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp2 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + bcm43xx_phy_write(bcm, 0x0015, backup[1]); + bcm43xx_radio_write16(bcm, 0x0051, backup[14]); + bcm43xx_radio_write16(bcm, 0x0052, backup[15]); + bcm43xx_radio_write16(bcm, 0x0043, backup[0]); + bcm43xx_phy_write(bcm, 0x005A, backup[16]); + bcm43xx_phy_write(bcm, 0x0059, backup[17]); + bcm43xx_phy_write(bcm, 0x0058, backup[18]); + bcm43xx_write16(bcm, 0x03E6, backup[11]); + if (phy->version != 0) + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); + bcm43xx_phy_write(bcm, 0x0035, backup[10]); + bcm43xx_radio_selectchannel(bcm, radio->channel, 1); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_phy_write(bcm, 0x0030, backup[2]); + bcm43xx_write16(bcm, 0x03EC, backup[3]); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, backup[4]); + bcm43xx_phy_write(bcm, 0x0812, backup[5]); + bcm43xx_phy_write(bcm, 0x0814, backup[6]); + bcm43xx_phy_write(bcm, 0x0815, backup[7]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); + bcm43xx_phy_write(bcm, 0x0802, backup[9]); + } + } + if (i >= 15) + ret = backup[13]; + + return ret; +} + +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm) +{ + int err; + + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_radio_write16(bcm, 0x0009, 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0032, 0x008F); + bcm43xx_radio_write16(bcm, 0x0006, 0x008F); + bcm43xx_radio_write16(bcm, 0x0034, 0x008F); + bcm43xx_radio_write16(bcm, 0x002C, 0x0007); + bcm43xx_radio_write16(bcm, 0x0082, 0x0080); + bcm43xx_radio_write16(bcm, 0x0080, 0x0000); + bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); + bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); + bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); + bcm43xx_phy_write(bcm, 0x0069, 0x07BE); + bcm43xx_phy_write(bcm, 0x006A, 0x0000); + + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); + assert(err == 0); + udelay(1000); +} + +static inline +u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, + u8 channel, + int synthetic_pu_workaround) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 r8, tmp; + u16 freq; + + if ((radio->manufact == 0x17F) && + (radio->version == 0x2060) && + (radio->revision == 1)) { + if (channel > 200) + return -EINVAL; + freq = channel2freq_a(channel); + + r8 = bcm43xx_radio_read16(bcm, 0x0008); + bcm43xx_write16(bcm, 0x03F0, freq); + bcm43xx_radio_write16(bcm, 0x0008, r8); + + TODO();//TODO: write max channel TX power? to Radio 0x2D + tmp = bcm43xx_radio_read16(bcm, 0x002E); + tmp &= 0x0080; + TODO();//TODO: OR tmp with the Power out estimation for this channel? + bcm43xx_radio_write16(bcm, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0022, + (bcm43xx_radio_read16(bcm, 0x0022) + & 0x000F) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0008, + (bcm43xx_radio_read16(bcm, 0x0008) + & 0x00F0) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0029, + (bcm43xx_radio_read16(bcm, 0x0029) + & 0xFF0F) | 0x00B0); + bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0036, 0x0085); + bcm43xx_radio_write16(bcm, 0x003A, + (bcm43xx_radio_read16(bcm, 0x003A) + & 0xFF20) | freq_r3A_value(freq)); + bcm43xx_radio_write16(bcm, 0x003D, + bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); + bcm43xx_radio_write16(bcm, 0x0081, + (bcm43xx_radio_read16(bcm, 0x0081) + & 0xFF7F) | 0x0080); + bcm43xx_radio_write16(bcm, 0x0035, + bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); + bcm43xx_radio_write16(bcm, 0x0035, + (bcm43xx_radio_read16(bcm, 0x0035) + & 0xFFEF) | 0x0010); + bcm43xx_radio_set_tx_iq(bcm); + TODO(); //TODO: TSSI2dbm workaround + bcm43xx_phy_xmitpower(bcm);//FIXME correct? + } else { + if ((channel < 1) || (channel > 14)) + return -EINVAL; + + if (synthetic_pu_workaround) + bcm43xx_synth_pu_workaround(bcm, channel); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); + + if (channel == 14) { + if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + & ~(1 << 7)); + } else { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + | (1 << 7)); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + & 0xF7BF); + } + } + + radio->channel = channel; + //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states + // that 2000 usecs might suffice. + udelay(8000); + + return 0; +} + +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val) +{ + u16 tmp; + + val <<= 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val); +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 bcm43xx_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 bcm43xx_get_txgain_dac(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) +{ + u16 pamp, base, dac, ilt; + + txpower = limit_value(txpower, 0, 63); + + pamp = bcm43xx_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + bcm43xx_phy_write(bcm, 0x0019, pamp); + + base = bcm43xx_get_txgain_base_band(txpower); + base &= 0x000F; + bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); + + ilt = bcm43xx_ilt_read16(bcm, 0x3001); + ilt &= 0x0007; + + dac = bcm43xx_get_txgain_dac(txpower); + dac <<= 3; + dac |= ilt; + + bcm43xx_ilt_write16(bcm, 0x3001, dac); + + bcm->current_core->radio->txpower[0] = txpower; + + TODO(); + //TODO: FuncPlaceholder (Adjust BB loft cancel) +} + +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 radio_attenuation, + u16 txpower) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (baseband_attenuation == 0xFFFF) + baseband_attenuation = radio->txpower[0]; + else + radio->txpower[0] = baseband_attenuation; + if (radio_attenuation == 0xFFFF) + radio_attenuation = radio->txpower[1]; + else + radio->txpower[1] = radio_attenuation; + if (txpower == 0xFFFF) + txpower = radio->txpower[2]; + else + radio->txpower[2] = txpower; + + assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); + if (radio->revision < 6) + assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); + else + assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); + assert(/*txpower >= 0 &&*/ txpower <= 7); + + bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); + bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F) + | (txpower << 4)); + } + if (phy->type == BCM43xx_PHYTYPE_G) + bcm43xx_phy_lo_adjust(bcm, 0); +} + + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int err; + + if (radio->enabled) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); + bcm43xx_radio_init2060(bcm); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_write(bcm, 0x0015, 0x8000); + bcm43xx_phy_write(bcm, 0x0015, 0xCC00); + bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); + assert(err == 0); + break; + default: + assert(0); + } + radio->enabled = 1; + dprintk(KERN_INFO PFX "Radio turned on\n"); +} + +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); + bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); + } + if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { + bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); + bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); + } else + bcm43xx_phy_write(bcm, 0x0015, 0xAA00); + radio->enabled = 0; + dprintk(KERN_INFO PFX "Radio turned off\n"); +} + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) +{ + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); + break; + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h new file mode 100644 index 00000000000..89fe2928214 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -0,0 +1,93 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_RADIO_H_ +#define BCM43xx_RADIO_H_ + +#include "bcm43xx.h" + + +#define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36 +#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6 + +/* Force antenna 0. */ +#define BCM43xx_RADIO_TXANTENNA_0 0 +/* Force antenna 1. */ +#define BCM43xx_RADIO_TXANTENNA_1 1 +/* Use the RX antenna, that was selected for the most recently + * received good PLCP header. + */ +#define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3 +#define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP + +#define BCM43xx_RADIO_INTERFMODE_NONE 0 +#define BCM43xx_RADIO_INTERFMODE_NONWLAN 1 +#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2 +#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3 + + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm); +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm); + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm); +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, + int synthetic_pu_workaround); + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 attenuation, + u16 txpower); +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel); +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm); + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode); + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm); +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm); +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val); +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_RADIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c new file mode 100644 index 00000000000..fe6409a9090 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -0,0 +1,1099 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include /* for capable() */ +#include + +#include "bcm43xx.h" +#include "bcm43xx_wx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" + +/* Define to enable a printk on each wx handler function invocation */ +//#define BCM43xx_WX_DEBUG + + +#ifdef BCM43xx_WX_DEBUG +# define printk_wx printk +#else +# define printk_wx(x...) do { /* nothing */ } while (0) +#endif +#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__); + +#define MAX_WX_STRING 80 + + +static int bcm43xx_wx_get_name(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int i, nr_80211; + struct bcm43xx_phyinfo *phy; + char suffix[7] = { 0 }; + int have_a = 0, have_b = 0, have_g = 0; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + nr_80211 = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < nr_80211; i++) { + phy = bcm->phy + i; + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + case BCM43xx_PHYTYPE_G: + have_g = 1; + case BCM43xx_PHYTYPE_B: + have_b = 1; + break; + default: + assert(0); + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + i = 0; + if (have_a) { + suffix[i++] = 'a'; + suffix[i++] = '/'; + } + if (have_b) { + suffix[i++] = 'b'; + suffix[i++] = '/'; + } + if (have_g) { + suffix[i++] = 'g'; + suffix[i++] = '/'; + } + if (i != 0) + suffix[i - 1] = '\0'; + + snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); + + return 0; +} + +static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211softmac_device *softmac = bcm->softmac; + unsigned long flags; + u8 channel; + int freq; + int err = 0; + + wx_enter(); + + if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { + channel = data->freq.m; + freq = bcm43xx_channel_to_freq(bcm, channel); + } else { + channel = bcm43xx_freq_to_channel(bcm, data->freq.m); + freq = data->freq.m; + } + if (!bcm43xx_is_valid_channel(bcm, channel)) + return -EINVAL; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->initialized) { + //ieee80211softmac_disassoc(softmac, $REASON); + bcm43xx_mac_suspend(bcm); + err = bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else + bcm->current_core->radio->initial_channel = channel; + spin_unlock_irqrestore(&bcm->lock, flags); + if (!err) + printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel); + + return err; +} + +static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -ENODEV; + u16 channel; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + channel = bcm->current_core->radio->channel; + if (channel == 0xFF) { + assert(!bcm->initialized); + channel = bcm->current_core->radio->initial_channel; + if (channel == 0xFF) + goto out_unlock; + } + assert(channel > 0 && channel <= 1000); + data->freq.e = 1; + data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; + data->freq.flags = 1; + + err = 0; +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_set_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + wx_enter(); + + mode = data->mode; + if (mode == IW_MODE_AUTO) + mode = BCM43xx_INITIAL_IWMODE; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->ieee->iw_mode != mode) + bcm43xx_set_iwmode(bcm, mode); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->mode = bcm->ieee->iw_mode; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct iw_range *range = (struct iw_range *)extra; + const struct ieee80211_geo *geo; + unsigned long flags; + int i, j; + + wx_enter(); + + data->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + //TODO: What about 802.11b? + /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ + range->throughput = 27 * 1000 * 1000; + + range->max_qual.qual = 100; + /* TODO: Real max RSSI */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = 7; + + range->avg_qual.qual = 70; + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; + + range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; + range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = WEP_KEYS; + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 16; + + spin_lock_irqsave(&bcm->lock, flags); + + range->num_bitrates = 0; + i = 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A || + bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates = 8; + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; + } + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B || + bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates += 4; + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; + } + + geo = ieee80211_get_geo(bcm->ieee); + range->num_channels = geo->a_channels + geo->bg_channels; + j = 0; + for (i = 0; i < geo->a_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->a[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + for (i = 0; i < geo->bg_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->bg[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + range->num_frequency = j; + + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); + memcpy(bcm->nick, extra, len); + bcm->nick[len] = '\0'; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + len = strlen(bcm->nick) + 1; + memcpy(extra, bcm->nick, len); + data->data.length = (__u16)len; + data->data.flags = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (data->rts.disabled) { + bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; + err = 0; + } else { + if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && + data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { + bcm->rts_threshold = data->rts.value; + err = 0; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->rts.value = bcm->rts_threshold; + data->rts.fixed = 0; + data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (data->frag.disabled) { + bcm->ieee->fts = MAX_FRAG_THRESHOLD; + err = 0; + } else { + if (data->frag.value >= MIN_FRAG_THRESHOLD && + data->frag.value <= MAX_FRAG_THRESHOLD) { + bcm->ieee->fts = data->frag.value & ~0x1; + err = 0; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->frag.value = bcm->ieee->fts; + data->frag.fixed = 0; + data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -ENODEV; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) + goto out_unlock; + if (data->power.disabled != (!(bcm->current_core->radio->enabled))) { + if (data->power.disabled) + bcm43xx_radio_turn_off(bcm); + else + bcm43xx_radio_turn_on(bcm); + } + //TODO: set txpower. + err = 0; + +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); +//TODO data->power.value = ??? + data->power.fixed = 1; + data->power.flags = IW_TXPOW_DBM; + data->power.disabled = !(bcm->current_core->radio->enabled); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_retry(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_retry(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_set_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_power(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_power(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode, err = 0; + + wx_enter(); + + mode = *((int *)extra); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + printk(KERN_ERR PFX "set_interfmode allowed parameters are: " + "0 => None, 1 => Non-WLAN, 2 => WLAN, " + "3 => Auto-WLAN\n"); + return -EINVAL; + } + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->initialized) { + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + } else { + if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { + printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " + "not supported while the interface is down.\n"); + err = -ENODEV; + } else + bcm->current_core->radio->interfmode = mode; + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + mode = bcm->current_core->radio->interfmode; + spin_unlock_irqrestore(&bcm->lock, flags); + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); + break; + default: + assert(0); + } + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + on = *((int *)extra); + spin_lock_irqsave(&bcm->lock, flags); + bcm->short_preamble = !!on; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + on = bcm->short_preamble; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (on) + strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); + else + strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + on = *((int *)extra); + spin_lock_irqsave(&bcm->lock, flags); + bcm->ieee->host_encrypt = !!on; + bcm->ieee->host_decrypt = !!on; + bcm->ieee->host_build_iv = !on; + + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + on = bcm->ieee->host_encrypt; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (on) + strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); + else + strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); + data->data.length = strlen(extra + 1); + + return 0; +} + +/* Enough buffer to hold a hexdump of the sprom data. */ +#define SPROM_BUFFERSIZE 512 + +static int sprom2hex(const u16 *sprom, char *dump) +{ + int i, pos = 0; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + u8 crc, expected_crc; + + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) + return -EINVAL; + while (cnt < BCM43xx_SPROM_SIZE) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); + return -EINVAL; + } + + return 0; +} + +static int bcm43xx_wx_sprom_read(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM, i; + u16 *sprom; + unsigned long flags; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + spin_lock_irqsave(&bcm->lock, flags); + err = -ENODEV; + if (!bcm->initialized) { + spin_unlock_irqrestore(&bcm->lock, flags); + goto out_kfree; + } + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + spin_unlock_irqrestore(&bcm->lock, flags); + + data->data.length = sprom2hex(sprom, extra); + + err = 0; +out_kfree: + kfree(sprom); +out: + return err; +} + +static int bcm43xx_wx_sprom_write(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM; + u16 *sprom; + unsigned long flags; + char *input; + unsigned int len; + u32 spromctl; + int i; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + len = data->data.length; + extra[len - 1] = '\0'; + input = strchr(extra, ':'); + if (input) { + input++; + len -= input - extra; + } else + input = extra; + err = hex2sprom(sprom, input, len); + if (err) + goto out_kfree; + + spin_lock_irqsave(&bcm->lock, flags); + err = -ENODEV; + if (!bcm->initialized) { + spin_unlock_irqrestore(&bcm->lock, flags); + goto out_kfree; + } + + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + spromctl |= 0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + /* We must burn lots of CPU cycles here, but that does not + * really matter as one does not write the SPROM every other minute... + */ + printk(KERN_INFO PFX "[ 0%%"); + mdelay(500); + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + if (i == 16) + printk("25%%"); + else if (i == 32) + printk("50%%"); + else if (i == 48) + printk("75%%"); + else if (i % 2) + printk("."); +//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mdelay(20); + } + spromctl &= ~0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + mdelay(500); + printk("100%% ]\n"); + printk(KERN_INFO PFX "SPROM written.\n"); + err = 0; +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); +out_kfree: + kfree(sprom); +out: + return err; +} + + +#ifdef WX +# undef WX +#endif +#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] +static const iw_handler bcm43xx_wx_handlers[] = { + /* Wireless Identification */ + WX(SIOCGIWNAME) = bcm43xx_wx_get_name, + /* Basic operations */ + WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, + WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, + WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, + WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, + /* Informative stuff */ + WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, + /* Access Point manipulation */ + WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, + WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, + WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, + WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, + /* 802.11 specific support */ + WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, + WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, + WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, + WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, + /* Other parameters */ + WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, + WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, + WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, + WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, + WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, + WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, + WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, + WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, +//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, +//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, + /* Encoding */ + WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, + WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, + WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, + WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, + /* Power saving */ +//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, +//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, + WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, + WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, + WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, + WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, +}; +#undef WX + +static const iw_handler bcm43xx_priv_wx_handlers[] = { + /* Set Interference Mitigation Mode. */ + bcm43xx_wx_set_interfmode, + /* Get Interference Mitigation Mode. */ + bcm43xx_wx_get_interfmode, + /* Enable/Disable Short Preamble mode. */ + bcm43xx_wx_set_shortpreamble, + /* Get Short Preamble mode. */ + bcm43xx_wx_get_shortpreamble, + /* Enable/Disable Software Encryption mode */ + bcm43xx_wx_set_swencryption, + /* Get Software Encryption mode */ + bcm43xx_wx_get_swencryption, + /* Write SRPROM data. */ + bcm43xx_wx_sprom_write, + /* Read SPROM data. */ + bcm43xx_wx_sprom_read, +}; + +#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) +#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) +#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) +#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) +#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) +#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) +#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) +#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) + +#define PRIV_WX_DUMMY(ioctl) \ + { \ + .cmd = (ioctl), \ + .name = "__unused" \ + } + +static const struct iw_priv_args bcm43xx_priv_wx_args[] = { + { + .cmd = PRIV_WX_SET_INTERFMODE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_interfmode", + }, + { + .cmd = PRIV_WX_GET_INTERFMODE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_interfmode", + }, + { + .cmd = PRIV_WX_SET_SHORTPREAMBLE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_shortpreambl", + }, + { + .cmd = PRIV_WX_GET_SHORTPREAMBLE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_shortpreambl", + }, + { + .cmd = PRIV_WX_SET_SWENCRYPTION, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_swencryption", + }, + { + .cmd = PRIV_WX_GET_SWENCRYPTION, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_swencryption", + }, + { + .cmd = PRIV_WX_SPROM_WRITE, + .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, + .name = "write_sprom", + }, + { + .cmd = PRIV_WX_SPROM_READ, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, + .name = "read_sprom", + }, +}; + +const struct iw_handler_def bcm43xx_wx_handlers_def = { + .standard = bcm43xx_wx_handlers, + .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), + .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), + .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), + .private = bcm43xx_priv_wx_handlers, + .private_args = bcm43xx_priv_wx_args, +}; + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h new file mode 100644 index 00000000000..1f29ff3aa4c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h @@ -0,0 +1,36 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_WX_H_ +#define BCM43xx_WX_H_ + +extern const struct iw_handler_def bcm43xx_wx_handlers_def; + +#endif /* BCM43xx_WX_H_ */ -- cgit v1.2.3-70-g09d2 From 70e5e983f8a3f801a96bfeb0682cd2955ec3c8ce Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 23 Jan 2006 17:00:39 -0500 Subject: [PATCH] bcm43xx: patch Kconfig and wireless/Makefile for import Patch Kconfig and wireless/Makefile to merge bcm43xx 'properly' Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 8 ++++++++ drivers/net/wireless/Makefile | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fd17aa8491b..7c7dca112bf 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -501,6 +501,14 @@ config PRISM54 source "drivers/net/wireless/hostap/Kconfig" +config BCM43XX + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL + select FW_LOADER + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 3a6f7ba326c..c8677987936 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ +obj-$(CONFIG_BCM43XX) += bcm43xx/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o -- cgit v1.2.3-70-g09d2 From ea72ab229fe9cdfe3d3f70a6e64d98c725294b24 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:26:20 +0100 Subject: [PATCH] bcm43xx: sync with svn.berlios.de Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 198 ++++++++++++--------------- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 11 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 7 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 8 +- 5 files changed, 102 insertions(+), 124 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index df19fbfa9ea..af5c27f9bfd 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -214,7 +214,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) return -ENOMEM; } if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " + "(0x%08x, len: %lu)\n", + ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, ring->vbase, ring->dmabase); return -ENOMEM; @@ -261,13 +263,6 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, return 0; } -static inline int dmacontroller_rx_reset(struct bcm43xx_dmaring *ring) -{ - assert(!ring->tx); - - return bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); -} - /* Reset the RX DMA channel */ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 mmio_base) @@ -308,13 +303,6 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, return 0; } -static inline int dmacontroller_tx_reset(struct bcm43xx_dmaring *ring) -{ - assert(ring->tx); - - return bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); -} - static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, struct bcm43xx_dmadesc *desc, struct bcm43xx_dmadesc_meta *meta, @@ -337,7 +325,9 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb_any(skb); - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " + "(0x%08x, len: %u)\n", + dmaaddr, ring->rx_buffersize); return -ENOMEM; } meta->skb = skb; @@ -365,7 +355,7 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) { int i, err = -ENOMEM; - struct bcm43xx_dmadesc *desc = NULL; + struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; for (i = 0; i < ring->nr_slots; i++) { @@ -375,24 +365,20 @@ static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); if (err) goto err_unwind; - - assert(ring->used_slots <= ring->nr_slots); } ring->used_slots = ring->nr_slots; - err = 0; out: return err; err_unwind: - for ( ; i >= 0; i--) { + for (i--; i >= 0; i--) { desc = ring->vbase + i; meta = ring->meta + i; unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb(meta->skb); } - ring->used_slots = 0; goto out; } @@ -442,13 +428,13 @@ out: static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) { if (ring->tx) { - dmacontroller_tx_reset(ring); + bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); /* Zero out Transmit Descriptor ring address. */ bcm43xx_write32(ring->bcm, ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, 0x00000000); } else { - dmacontroller_rx_reset(ring); + bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); /* Zero out Receive Descriptor ring address. */ bcm43xx_write32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, @@ -508,9 +494,7 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, if (bcm->pci_dev->bus->number == 0) ring->memoffset = 0; #endif - - - spin_lock_init(&ring->lock); + ring->bcm = bcm; ring->nr_slots = nr_descriptor_slots; ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; @@ -578,22 +562,25 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring1); - bcm->current_core->dma->rx_ring1 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); - bcm->current_core->dma->rx_ring0 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); - bcm->current_core->dma->tx_ring3 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); - bcm->current_core->dma->tx_ring2 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); - bcm->current_core->dma->tx_ring1 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); - bcm->current_core->dma->tx_ring0 = NULL; + struct bcm43xx_dma *dma = bcm->current_core->dma; + + bcm43xx_destroy_dmaring(dma->rx_ring1); + dma->rx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; } int bcm43xx_dma_init(struct bcm43xx_private *bcm) { + struct bcm43xx_dma *dma = bcm->current_core->dma; struct bcm43xx_dmaring *ring; int err = -ENOMEM; @@ -602,39 +589,39 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) BCM43xx_TXRING_SLOTS, 1); if (!ring) goto out; - bcm->current_core->dma->tx_ring0 = ring; + dma->tx_ring0 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx0; - bcm->current_core->dma->tx_ring1 = ring; + dma->tx_ring1 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx1; - bcm->current_core->dma->tx_ring2 = ring; + dma->tx_ring2 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx2; - bcm->current_core->dma->tx_ring3 = ring; + dma->tx_ring3 = ring; /* setup RX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, BCM43xx_RXRING_SLOTS, 0); if (!ring) goto err_destroy_tx3; - bcm->current_core->dma->rx_ring0 = ring; + dma->rx_ring0 = ring; if (bcm->current_core->rev < 5) { ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, BCM43xx_RXRING_SLOTS, 0); if (!ring) goto err_destroy_rx0; - bcm->current_core->dma->rx_ring1 = ring; + dma->rx_ring1 = ring; } dprintk(KERN_INFO PFX "DMA initialized\n"); @@ -643,27 +630,26 @@ out: return err; err_destroy_rx0: - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); - bcm->current_core->dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; err_destroy_tx3: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); - bcm->current_core->dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; err_destroy_tx2: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); - bcm->current_core->dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; err_destroy_tx1: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); - bcm->current_core->dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; err_destroy_tx0: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); - bcm->current_core->dma->tx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; goto out; } /* Generate a cookie for the TX header. */ -static inline -u16 generate_cookie(struct bcm43xx_dmaring *ring, - int slot) +static u16 generate_cookie(struct bcm43xx_dmaring *ring, + int slot) { u16 cookie = 0x0000; @@ -693,24 +679,25 @@ u16 generate_cookie(struct bcm43xx_dmaring *ring, } /* Inspect a cookie and find out to which controller/slot it belongs. */ -static inline +static struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, int *slot) { + struct bcm43xx_dma *dma = bcm->current_core->dma; struct bcm43xx_dmaring *ring = NULL; switch (cookie & 0xF000) { case 0x0000: - ring = bcm->current_core->dma->tx_ring0; + ring = dma->tx_ring0; break; case 0x1000: - ring = bcm->current_core->dma->tx_ring1; + ring = dma->tx_ring1; break; case 0x2000: - ring = bcm->current_core->dma->tx_ring2; + ring = dma->tx_ring2; break; case 0x3000: - ring = bcm->current_core->dma->tx_ring3; + ring = dma->tx_ring3; break; default: assert(0); @@ -721,8 +708,8 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, return ring; } -static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, - int slot) +static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, + int slot) { /* Everything is ready to start. Buffers are DMA mapped and * associated with slots. @@ -736,11 +723,10 @@ static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, (u32)(slot * sizeof(struct bcm43xx_dmadesc))); } -static inline -int dma_tx_fragment(struct bcm43xx_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_txb *txb, - u8 cur_frag) +static int dma_tx_fragment(struct bcm43xx_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_txb *txb, + u8 cur_frag) { int slot; struct bcm43xx_dmadesc *desc; @@ -777,7 +763,9 @@ int dma_tx_fragment(struct bcm43xx_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { return_slot(ring, slot); - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " + "(0x%08x, len: %u)\n", + meta->dmaaddr, skb->len); return -ENOMEM; } @@ -797,14 +785,15 @@ int dma_tx_fragment(struct bcm43xx_dmaring *ring, return 0; } -static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, - struct ieee80211_txb *txb) +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) { /* We just received a packet from the kernel network subsystem. * Add headers and DMA map the memory. Poke * the device to send the stuff. * Note that this is called from atomic context. */ + struct bcm43xx_dmaring *ring = bcm->current_core->dma->tx_ring1; u8 i; struct sk_buff *skb; @@ -818,8 +807,6 @@ static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, return -ENOMEM; } - assert(irqs_disabled()); - spin_lock(&ring->lock); for (i = 0; i < txb->nr_frags; i++) { skb = txb->fragments[i]; /* We do not free the skb, as it is freed as @@ -829,22 +816,12 @@ static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, dma_tx_fragment(ring, skb, txb, i); //TODO: handle failure of dma_tx_fragment } - spin_unlock(&ring->lock); return 0; } -int fastcall -bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return dma_transfer_txb(bcm->current_core->dma->tx_ring1, - txb); -} - -void fastcall -bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; @@ -855,9 +832,6 @@ bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, ring = parse_cookie(bcm, status->cookie, &slot); assert(ring); assert(ring->tx); - assert(irqs_disabled()); - spin_lock(&ring->lock); - assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); while (1) { assert(slot >= 0 && slot < ring->nr_slots); @@ -877,13 +851,10 @@ bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, slot = next_slot(ring, slot); } bcm->stats.last_tx = jiffies; - - spin_unlock(&ring->lock); } -static inline -void dma_rx(struct bcm43xx_dmaring *ring, - int *slot) +static void dma_rx(struct bcm43xx_dmaring *ring, + int *slot) { struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; @@ -928,8 +899,12 @@ void dma_rx(struct bcm43xx_dmaring *ring, barrier(); len = le16_to_cpu(rxhdr->frame_length); } while (len == 0 && i++ < 5); - if (len == 0) + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); goto drop; + } } if (unlikely(len > ring->rx_buffersize)) { /* The data did not fit into one descriptor buffer @@ -937,15 +912,24 @@ void dma_rx(struct bcm43xx_dmaring *ring, * This should never happen, as we try to allocate buffers * big enough. So simply ignore this packet. */ - int cnt = 1; - s32 tmp = len - ring->rx_buffersize; - - for ( ; tmp > 0; tmp -= ring->rx_buffersize) { + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); *slot = next_slot(ring, *slot); cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; } - printkl(KERN_ERR PFX "DMA RX buffer too small. %d dropped.\n", - cnt); + printkl(KERN_ERR PFX "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); goto drop; } len -= IEEE80211_FCS_LEN; @@ -954,6 +938,8 @@ void dma_rx(struct bcm43xx_dmaring *ring, err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); if (unlikely(err)) { dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, + ring->rx_buffersize); goto drop; } @@ -971,8 +957,7 @@ drop: return; } -void fastcall -bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) { u32 status; u16 descptr; @@ -982,9 +967,6 @@ bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) #endif assert(!ring->tx); - assert(irqs_disabled()); - spin_lock(&ring->lock); - status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); current_slot = descptr / sizeof(struct bcm43xx_dmadesc); @@ -1002,8 +984,6 @@ bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, (u32)(slot * sizeof(struct bcm43xx_dmadesc))); ring->current_slot = slot; - - spin_unlock(&ring->lock); } /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index e32cf68f8e1..93e99d61f2e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -122,7 +122,6 @@ struct bcm43xx_dmadesc_meta { }; struct bcm43xx_dmaring { - spinlock_t lock; struct bcm43xx_private *bcm; /* Kernel virtual base address of the ring memory. */ struct bcm43xx_dmadesc *vbase; @@ -166,11 +165,11 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 dmacontroller_mmio_base); -int FASTCALL(bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb)); -void FASTCALL(bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status)); +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); -void FASTCALL(bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)); +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); #endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index be60a6509f2..4b4e60a22c0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -4097,7 +4097,6 @@ int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, } frame_ctl = le16_to_cpu(wlhdr->frame_ctl); - if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { frame_ctl &= ~IEEE80211_FCTL_PROTECTED; wlhdr->frame_ctl = cpu_to_le16(frame_ctl); @@ -4113,12 +4112,12 @@ int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, skb_trim(skb, skb->len - 4); stats.len -= 8; } - /* do _not_ use wlhdr again without reassigning it */ + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); } switch (WLAN_FC_GET_TYPE(frame_ctl)) { case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(bcm->ieee, skb->data, &stats); + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); break; case IEEE80211_FTYPE_DATA: if (is_packet_for_us) @@ -4143,7 +4142,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, if (bcm->pio_mode) err = bcm43xx_pio_transfer_txb(bcm, txb); else - err = bcm43xx_dma_transfer_txb(bcm, txb); + err = bcm43xx_dma_tx(bcm, txb); return err; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 41b9cd7fc9e..f5e7a6ab93c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1161,7 +1161,7 @@ void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) phy->minlowsigpos[1] += 0x0101; bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); - if (radio->version == 2053) { + if (radio->version == 0x2053) { bcm43xx_phy_write(bcm, 0x000A, regstack[2]); bcm43xx_phy_write(bcm, 0x002A, regstack[3]); bcm43xx_phy_write(bcm, 0x0035, regstack[4]); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 1e65658552b..5ce6acef2c4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -467,8 +467,8 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) | 0x0040); - bcm43xx_phy_write(bcm, 0x007A, - bcm43xx_phy_read(bcm, 0x007A) | 0x000F); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); bcm43xx_set_all_gains(bcm, 3, 0, 1); bcm43xx_radio_write16(bcm, 0x0043, (bcm43xx_radio_read16(bcm, 0x0043) @@ -761,8 +761,8 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); bcm43xx_set_original_gains(bcm); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) | 0x8000); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); if (phy->rev >= 3) { bcm43xx_phy_write(bcm, 0x0801, backup[14]); bcm43xx_phy_write(bcm, 0x0060, backup[15]); -- cgit v1.2.3-70-g09d2 From 4a2a2792d0cb3f2797ff179beef7b8c2981979c2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:33:15 +0100 Subject: [PATCH] bcm43xx: remove linux version compatibility code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index aca1601e5b4..38e75ed2b65 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -935,27 +935,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) - -/* - * Compatibility stuff follows - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) -# error "The bcm43xx driver does not support kernels < 2.6.15" -# error "The driver will _NOT_ compile on your kernel. Please upgrade to the latest 2.6 kernel." -# error "DO NOT COMPLAIN ABOUT BUGS. UPDATE FIRST AND TRY AGAIN." -#else -# if !defined(CONFIG_IEEE80211_MODULE) && !defined(CONFIG_IEEE80211) -# error "Generic IEEE 802.11 Networking Stack (CONFIG_IEEE80211) not available." -# endif -#endif -#ifdef IEEE80211SOFTMAC_API -# if IEEE80211SOFTMAC_API != 0 -# warning "Incompatible SoftMAC subsystem installed." -# endif -#else -# error "The bcm43xx driver requires the SoftMAC subsystem." -# error "SEE >>>>>> http://softmac.sipsolutions.net/ <<<<<<" -#endif - #endif /* BCM43xx_H_ */ -- cgit v1.2.3-70-g09d2 From 08ccd883f536d81d380522106c67bd5d7043fa4a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:37:05 +0100 Subject: [PATCH] bcm43xx: Move README file to Documentation directory. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- Documentation/networking/bcm43xx.txt | 36 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/README | 36 ------------------------------------ 2 files changed, 36 insertions(+), 36 deletions(-) create mode 100644 Documentation/networking/bcm43xx.txt delete mode 100644 drivers/net/wireless/bcm43xx/README (limited to 'drivers') diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt new file mode 100644 index 00000000000..64d9022de7f --- /dev/null +++ b/Documentation/networking/bcm43xx.txt @@ -0,0 +1,36 @@ + + BCM43xx Linux Driver Project + ============================ + +About this software +------------------- + +The goal of this project is to develop a linux driver for Broadcom +BCM43xx chips, based on the specification at +http://bcm-specs.sipsolutions.net/ + +The project page is http://bcm43xx.berlios.de/ + + +Requirements +------------ + +1) Linux Kernel 2.6.15 or later + http://www.kernel.org/ + + You may want to configure your kernel with: + + CONFIG_DEBUG_FS (optional): + -> Kernel hacking + -> Debug Filesystem + +2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 + modules: + http://softmac.sipsolutions.net/ + +3) Firmware Files + + Please try fwcutter. Fwcutter can extract the firmware from various + binary driver files. It supports driver files from Windows, MacOS and + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. + Also, fwcutter comes with a README file for further instructions. diff --git a/drivers/net/wireless/bcm43xx/README b/drivers/net/wireless/bcm43xx/README deleted file mode 100644 index 64d9022de7f..00000000000 --- a/drivers/net/wireless/bcm43xx/README +++ /dev/null @@ -1,36 +0,0 @@ - - BCM43xx Linux Driver Project - ============================ - -About this software -------------------- - -The goal of this project is to develop a linux driver for Broadcom -BCM43xx chips, based on the specification at -http://bcm-specs.sipsolutions.net/ - -The project page is http://bcm43xx.berlios.de/ - - -Requirements ------------- - -1) Linux Kernel 2.6.15 or later - http://www.kernel.org/ - - You may want to configure your kernel with: - - CONFIG_DEBUG_FS (optional): - -> Kernel hacking - -> Debug Filesystem - -2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 - modules: - http://softmac.sipsolutions.net/ - -3) Firmware Files - - Please try fwcutter. Fwcutter can extract the firmware from various - binary driver files. It supports driver files from Windows, MacOS and - Linux. You can get fwcutter from http://bcm43xx.berlios.de/. - Also, fwcutter comes with a README file for further instructions. -- cgit v1.2.3-70-g09d2 From dda207ae2da37032524bbdd7a0133c37f2907ae8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:39:44 +0100 Subject: [PATCH] bcm43xx: remove redundant COPYING file. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/COPYING | 340 ----------------------------------- 1 file changed, 340 deletions(-) delete mode 100644 drivers/net/wireless/bcm43xx/COPYING (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/COPYING b/drivers/net/wireless/bcm43xx/COPYING deleted file mode 100644 index 5b6e7c66c27..00000000000 --- a/drivers/net/wireless/bcm43xx/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. -- cgit v1.2.3-70-g09d2 From 6f3e2045cabd952a86bc819181d8a190cd0689c3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 30 Jan 2006 17:43:20 +0100 Subject: [PATCH] bcm43xx: add DEBUG Kconfig option. Also fix indention. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7c7dca112bf..3b1363c9719 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -502,12 +502,21 @@ config PRISM54 source "drivers/net/wireless/hostap/Kconfig" config BCM43XX - tristate "Broadcom BCM43xx wireless support" - depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL select FW_LOADER - ---help--- - This is an experimental driver for the Broadcom 43xx wireless chip, - found in the Apple Airport Extreme and various other devices. + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + +config BCM43XX_DEBUG + bool "Broadcom BCM43xx debugging (RECOMMENDED)" + depends on BCM43XX + default y + ---help--- + Broadcom 43xx debugging messages. + Say Y, because the driver is still very experimental and + this will help you get it running. # yes, this works even when no drivers are selected config NET_WIRELESS -- cgit v1.2.3-70-g09d2 From 65f3f19120cf32233f537562e69893b88727b634 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 31 Jan 2006 20:11:38 +0100 Subject: [PATCH] bcm43xx: Fix makefile. Remove all the "out-of-tree" stuff. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 87 ++------------------------ drivers/net/wireless/bcm43xx/bcm43xx.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 8 +-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 11 ++-- 4 files changed, 14 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 98d4efb1d12..3e5ed77835e 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -1,87 +1,8 @@ -# Makefile for bcm43xx driver +obj-$(CONFIG_BCM43XX) += bcm43xx.o +bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o -VERSION := 0.0.1 -RELEASE_NAME := bcm43xx-$(VERSION) - -# Optional path, where the SoftMAC subsystem is located. -# You may set SOFTMAC_DIR in your bashrc, for example. -SOFTMAC_DIR ?= - -KVER := $(shell uname -r) -KDIR ?= /lib/modules/$(KVER)/build -PWD := $(shell pwd) -MODPATH := $(DESTDIR)/lib/modules/$(KVER)/kernel/drivers/net/bcm43xx - -# Comment/uncomment to enable/disable debugging -DEBUG = y - - -ifeq ($(DEBUG),y) -DEBUGFS_OBJ = bcm43xx_debugfs.o -CFLAGS += -O2 -DCONFIG_BCM43XX_DEBUG -else -DEBUGFS_OBJ = -CFLAGS += -O2 -endif - -CFLAGS += -DBCM43xx_VERSION=$(VERSION) -I/lib/modules/$(KVER)/include -ifneq ($(SOFTMAC_DIR),) -CPPFLAGS := -I$(SOFTMAC_DIR) $(CPPFLAGS) -endif - -ifneq ($(KERNELRELEASE),) -# call from kernel build system - -obj-m := bcm43xx.o -bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o $(DEBUGFS_OBJ) \ +bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_pio.o bcm43xx_ilt.o \ - bcm43xx_leds.o - -else - -default: modules - -modules: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -install: bcm43xx.ko - install -d $(MODPATH) - install -m 644 -c bcm43xx.ko $(MODPATH) - /sbin/depmod -a - -uninstall: - rm -rf $(MODPATH) - /sbin/depmod -a - -endif - -clean: - find . \( -name '*.ko' -o -name '*.o' -o -name '.tmp_versions' -o -name '*~' -o -name '.*.cmd' \ - -o -name '*.mod.c' -o -name '*.tar.bz2' -o -name '*.rej' -o -name '*.orig' \)\ - -print | xargs rm -Rf - -depend .depend dep: - $(CC) $(CFLAGS) -M *.c > .depend - -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - -DISTFILES = $(shell find . \( -not -name '.' \) -print | grep -v "\.tar\.bz2" | grep -v "\/\." ) -DISTDIR = $(RELEASE_NAME) - -release: clean - @rm -rf $(DISTDIR) - @mkdir $(DISTDIR) - @chmod 777 $(DISTDIR) - @for file in $(DISTFILES); do \ - if test -d $$file; then \ - mkdir $(DISTDIR)/$$file; \ - else \ - cp -p $$file $(DISTDIR)/$$file; \ - fi; \ - done - @tar -c $(DISTDIR) | bzip2 -9 > $(RELEASE_NAME).tar.bz2 - @rm -rf $(DISTDIR) + bcm43xx_leds.o $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 38e75ed2b65..7b97d8bf79e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -17,14 +17,10 @@ #include "bcm43xx_leds.h" -#define DRV_NAME __stringify(KBUILD_MODNAME) -#define DRV_VERSION __stringify(BCM43xx_VERSION) -#define BCM43xx_DRIVER_NAME DRV_NAME " driver " DRV_VERSION -#define PFX DRV_NAME ": " +#define PFX KBUILD_MODNAME ": " #define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 #define BCM43xx_IRQWAIT_MAX_RETRIES 50 -#define BCM43xx_TX_TIMEOUT (10 * HZ) #define BCM43xx_IO_SIZE 8192 #define BCM43xx_REG_ACTIVE_CORE 0x80 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index f8cfc84ca0d..5a7dc43cd67 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -141,7 +141,7 @@ static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, down(&big_buffer_sem); /* This is where the information is written to the "driver" file */ - fappend(BCM43xx_DRIVER_NAME "\n"); + fappend(KBUILD_MODNAME " driver\n"); fappend("Compiled at: %s %s\n", __DATE__, __TIME__); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); @@ -433,12 +433,12 @@ void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, void bcm43xx_debugfs_init(void) { memset(&fs, 0, sizeof(fs)); - fs.root = debugfs_create_dir(DRV_NAME, NULL); + fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); if (!fs.root) - printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "\" subdir failed!\n"); + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); if (!fs.dentry_driverinfo) - printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "/driver\" failed!\n"); + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); } void bcm43xx_debugfs_exit(void) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4b4e60a22c0..cfb0f0a485a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2471,7 +2471,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) } #endif res = request_irq(bcm->irq, bcm43xx_interrupt_handler, - SA_SHIRQ, DRV_NAME, bcm); + SA_SHIRQ, KBUILD_MODNAME, bcm); if (res) { printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); return -EFAULT; @@ -3809,7 +3809,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) } #endif - err = pci_request_regions(pci_dev, DRV_NAME); + err = pci_request_regions(pci_dev, KBUILD_MODNAME); if (err) { printk(KERN_ERR PFX "could not access PCI resources (%i)\n", err); @@ -4389,12 +4389,11 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, #endif net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; net_dev->irq = pdev->irq; - net_dev->watchdog_timeo = BCM43xx_TX_TIMEOUT; /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); memset(bcm, 0, sizeof(*bcm)); - wq = create_workqueue(DRV_NAME "_wq"); + wq = create_workqueue(KBUILD_MODNAME "_wq"); if (!wq) { err = -ENOMEM; goto err_free_netdev; @@ -4567,7 +4566,7 @@ static int bcm43xx_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ static struct pci_driver bcm43xx_pci_driver = { - .name = BCM43xx_DRIVER_NAME, + .name = KBUILD_MODNAME, .id_table = bcm43xx_pci_tbl, .probe = bcm43xx_init_one, .remove = __devexit_p(bcm43xx_remove_one), @@ -4579,7 +4578,7 @@ static struct pci_driver bcm43xx_pci_driver = { static int __init bcm43xx_init(void) { - printk(KERN_INFO BCM43xx_DRIVER_NAME "\n"); + printk(KERN_INFO KBUILD_MODNAME " driver\n"); bcm43xx_debugfs_init(); return pci_register_driver(&bcm43xx_pci_driver); } -- cgit v1.2.3-70-g09d2 From a4a600d3e17f450666a9086465122103e96140d7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 1 Feb 2006 22:09:52 +0100 Subject: [PATCH] bcm43xx: Add more initvals sanity checks and error out, if one sanity check fails. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 62 ++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index cfb0f0a485a..521777f56a3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2229,9 +2229,9 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } -static void bcm43xx_release_firmware(struct bcm43xx_private *bcm) +static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) { - if (bcm->firmware_norelease) + if (bcm->firmware_norelease && !force) return; /* Suspending or controller reset. */ release_firmware(bcm->ucode); bcm->ucode = NULL; @@ -2361,7 +2361,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) out: return err; error: - bcm43xx_release_firmware(bcm); + bcm43xx_release_firmware(bcm, 1); goto out; err_noinitval: printk(KERN_ERR PFX "Error: No InitVals available!\n"); @@ -2409,9 +2409,9 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) #endif } -static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, - const struct bcm43xx_initval *data, - const unsigned int len) +static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, + const struct bcm43xx_initval *data, + const unsigned int len) { u16 offset, size; u32 value; @@ -2422,35 +2422,54 @@ static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, size = be16_to_cpu(data[i].size); value = be32_to_cpu(data[i].value); - if (size == 2) - bcm43xx_write16(bcm, offset, value); - else if (size == 4) + if (unlikely(offset >= 0x1000)) + goto err_format; + if (size == 2) { + if (unlikely(value & 0xFFFF0000)) + goto err_format; + bcm43xx_write16(bcm, offset, (u16)value); + } else if (size == 4) { bcm43xx_write32(bcm, offset, value); - else - printk(KERN_ERR PFX "InitVals fileformat error.\n"); + } else + goto err_format; } + + return 0; + +err_format: + printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " + "Please fix your bcm43xx firmware files.\n"); + return -EPROTO; } -static void bcm43xx_upload_initvals(struct bcm43xx_private *bcm) +static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) { + int err; + #ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT bcm43xx_mmioprint_enable(bcm); #else bcm43xx_mmioprint_disable(bcm); #endif - bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, - bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; if (bcm->initvals1) { - bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, - bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; } +out: #ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT bcm43xx_mmioprint_disable(bcm); #else bcm43xx_mmioprint_enable(bcm); #endif + return err; } static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) @@ -2683,7 +2702,7 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) bcm43xx_leds_exit(bcm); bcm43xx_gpio_cleanup(bcm); free_irq(bcm->irq, bcm); - bcm43xx_release_firmware(bcm); + bcm43xx_release_firmware(bcm, 0); } /* Initialize the chip @@ -2708,13 +2727,15 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) err = bcm43xx_initialize_irq(bcm); if (err) - goto out; + goto err_release_fw; err = bcm43xx_gpio_init(bcm); if (err) goto err_free_irq; - bcm43xx_upload_initvals(bcm); + err = bcm43xx_upload_initvals(bcm); + if (err) + goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); if (modparam_noleds) @@ -2813,9 +2834,12 @@ out: err_radio_off: bcm43xx_radio_turn_off(bcm); +err_gpio_cleanup: bcm43xx_gpio_cleanup(bcm); err_free_irq: free_irq(bcm->irq, bcm); +err_release_fw: + bcm43xx_release_firmware(bcm, 1); goto out; } -- cgit v1.2.3-70-g09d2 From 9e4a375b15c9940b13e66e224570b35c471c0128 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 18:43:25 +0100 Subject: [PATCH] bcm43xx: Remove function bcm43xx_channel_is_allowed() Geographical restriction should become part of the 80211 stack, so every driver does not have to duplicate it. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 166 +--------------------------- 1 file changed, 1 insertion(+), 165 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 521777f56a3..c0ec503102c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -82,10 +82,6 @@ static int modparam_locale = -1; module_param_named(locale, modparam_locale, int, 0444); MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); -static int modparam_outdoor; -module_param_named(outdoor, modparam_outdoor, int, 0444); -MODULE_PARM_DESC(outdoor, "Set to 1, if you are using the device outdoor, 0 otherwise."); - static int modparam_noleds; module_param_named(noleds, modparam_noleds, int, 0444); MODULE_PARM_DESC(noleds, "Turn off all LED activity"); @@ -1088,163 +1084,13 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) return 0; } -static int bcm43xx_channel_is_allowed(struct bcm43xx_private *bcm, u8 channel, - u8 *max_power, u8 *flags) -{ - /* THIS FUNCTION DOES _NOT_ ENFORCE REGULATORY DOMAIN COMPLIANCE. - * It is only a helper function to make life easier to - * select legal channels and transmission powers. - */ - - u8 phytype = bcm->current_core->phy->type; - int allowed = 0; - - *max_power = 0; - *flags = 0; - - //FIXME: Set max_power and maybe flags - /*FIXME: Allowed channels are sometimes different for outdoor - * or indoor use. See modparam_outdoor. - */ - /* From b specs Max Power BPHY: - * USA: 1000mW - * Europe: 100mW - * Japan: 10mW/MHz - */ - - switch (bcm->sprom.locale) { - case BCM43xx_LOCALE_WORLD: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_THAILAND: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_ISRAEL: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 5 && channel <= 7) - allowed = 1; - } else { - if (channel >= 5 && channel <= 7) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JORDAN: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 10 && channel <= 13) - allowed = 1; - } else { - if (channel >= 10 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_CHINA: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JAPAN: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - //FIXME: This seems to be wrong. - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - //FIXME: This seems to be wrong. - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_USA_CANADA_ANZ: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 11) - allowed = 1; - } - break; - case BCM43xx_LOCALE_EUROPE: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_USA_LOW: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 11) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JAPAN_HIGH: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - //FIXME? - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_ALL: - allowed = 1; - break; - case BCM43xx_LOCALE_NONE: - break; - default: - assert(0); - } - - return allowed; -} - static void bcm43xx_geo_init(struct bcm43xx_private *bcm) { struct ieee80211_geo geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; int i, num80211; - u8 channel, flags, max_power; + u8 channel; struct bcm43xx_phyinfo *phy; const char *iso_country; @@ -1268,27 +1114,17 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_a) { for (i = 0, channel = 0; channel < 201; channel++) { - if (!bcm43xx_channel_is_allowed(bcm, channel, - &max_power, &flags)) - continue; chan = &geo.a[i++]; chan->freq = bcm43xx_channel_to_freq(bcm, channel); chan->channel = channel; - chan->flags = flags; - chan->max_power = max_power; } geo.a_channels = i; } if (have_bg) { for (i = 0, channel = 1; channel < 15; channel++) { - if (!bcm43xx_channel_is_allowed(bcm, channel, - &max_power, &flags)) - continue; chan = &geo.bg[i++]; chan->freq = bcm43xx_channel_to_freq(bcm, channel); chan->channel = channel; - chan->flags = flags; - chan->max_power = max_power; } geo.bg_channels = i; } -- cgit v1.2.3-70-g09d2 From 6465ce1bbf7fede82dccec342417105b10793b51 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 19:11:08 +0100 Subject: [PATCH] bcm43xx: basic ethtool support This patch contains the beginnings of ethtool support for bcm43xx. It only implements get_drvinfo and get_link, but that's enough for ifplugd to use ethtool to know whether we're associated or not and then start or stop dhcp as necessary. Signed-off-by: Jason Lunz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 3 +- drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c | 50 ++++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h | 8 +++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 ++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 3e5ed77835e..e025e9f052b 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -5,4 +5,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_pio.o bcm43xx_ilt.o \ - bcm43xx_leds.o $(bcm43xx-obj-y) + bcm43xx_leds.o bcm43xx_ethtool.o \ + $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c new file mode 100644 index 00000000000..b3ffcf50131 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c @@ -0,0 +1,50 @@ +/* + + Broadcom BCM43xx wireless driver + + ethtool support + + Copyright (c) 2006 Jason Lunz + + Some code in this file is derived from the 8139too.c driver + Copyright (C) 2002 Jeff Garzik + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ethtool.h" + +#include +#include +#include +#include + + +static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(dev); + + strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + strncpy(info->version, UTS_RELEASE, sizeof(info->version)); + strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); +} + +struct ethtool_ops bcm43xx_ethtool_ops = { + .get_drvinfo = bcm43xx_get_drvinfo, + .get_link = ethtool_op_get_link, +}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h new file mode 100644 index 00000000000..813704991f6 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h @@ -0,0 +1,8 @@ +#ifndef BCM43xx_ETHTOOL_H_ +#define BCM43xx_ETHTOOL_H_ + +#include + +extern struct ethtool_ops bcm43xx_ethtool_ops; + +#endif /* BCM43xx_ETHTOOL_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index c0ec503102c..1051a49ddaf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -49,6 +49,7 @@ #include "bcm43xx_pio.h" #include "bcm43xx_power.h" #include "bcm43xx_wx.h" +#include "bcm43xx_ethtool.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); @@ -4249,6 +4250,7 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, #endif net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; net_dev->irq = pdev->irq; + SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops); /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); -- cgit v1.2.3-70-g09d2 From 8fa252d099d864f8848a9890f26d1a51a9c7ad32 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 19:49:15 +0100 Subject: [PATCH] bcm43xx: Wireless Ext update Wireless Ext update: update we_version_source set enc_capa Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index fe6409a9090..c1d788d50f4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -41,6 +41,11 @@ #include "bcm43xx_main.h" #include "bcm43xx_radio.h" + +/* The WIRELESS_EXT version, which is implemented by this driver. */ +#define BCM43xx_WX_VERSION 18 + + /* Define to enable a printk on each wx handler function invocation */ //#define BCM43xx_WX_DEBUG @@ -282,7 +287,12 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->max_encoding_tokens = WEP_KEYS; range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = BCM43xx_WX_VERSION; + + range->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP; spin_lock_irqsave(&bcm->lock, flags); -- cgit v1.2.3-70-g09d2 From 67093a65c08dc45374f642b1ec1b86e7095a4dc8 Mon Sep 17 00:00:00 2001 From: Danny van Dyk Date: Wed, 1 Feb 2006 00:43:05 +0100 Subject: [PATCH] Sync bcm43xx_phy_initb6() with specs Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 15 ++++++++++----- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index f5e7a6ab93c..d90f207b247 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -947,7 +947,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0050, 0x0020); if ((bcm->current_core->radio->manufact == 0x17F) && (bcm->current_core->radio->version == 0x2050) && - (bcm->current_core->radio->revision == 2)) { + (bcm->current_core->radio->revision <= 2)) { bcm43xx_radio_write16(bcm, 0x0050, 0x0020); bcm43xx_radio_write16(bcm, 0x005A, 0x0070); bcm43xx_radio_write16(bcm, 0x005B, 0x007B); @@ -984,10 +984,15 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x03E4, 0x0009); if (phy->type == BCM43xx_PHYTYPE_B) { bcm43xx_write16(bcm, 0x03E6, 0x8140); - bcm43xx_phy_write(bcm, 0x0016, 0x5410); - bcm43xx_phy_write(bcm, 0x0017, 0xA820); - bcm43xx_phy_write(bcm, 0x0007, 0x0062); - TODO();//TODO: calibrate stuff. + bcm43xx_phy_write(bcm, 0x0016, 0x0410); + bcm43xx_phy_write(bcm, 0x0017, 0x0820); + bcm43xx_phy_write(bcm, 0x0062, 0x0007); + (void) bcm43xx_radio_calibrationvalue(bcm); + bcm43xx_phy_lo_b_measure(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } bcm43xx_phy_init_pctl(bcm); } else bcm43xx_write16(bcm, 0x03E6, 0x0); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 5ce6acef2c4..3901aa99466 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1184,7 +1184,7 @@ int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, return 0; } -static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) { u16 reg, index, ret; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index 89fe2928214..a5d2e10d5d9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -89,5 +89,6 @@ void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm); #endif /* BCM43xx_RADIO_H_ */ -- cgit v1.2.3-70-g09d2 From 393344f67b598aaed594b9006e9eaa44ab62caa0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 5 Feb 2006 15:28:20 +0100 Subject: [PATCH] bcm43xx: fix txpower reporting in WE. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 2 ++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +++ drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 9 ++---- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 44 +++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 7b97d8bf79e..981d563f573 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -525,6 +525,8 @@ struct bcm43xx_radioinfo { * 3: tx_CTL2 */ u16 txpower[4]; + /* Desired TX power in dBm Q5.2 */ + u16 txpower_desired; /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 1051a49ddaf..8e08c41f86d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -793,6 +793,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) bcm->current_core->radio->txpower[2] = 3; else bcm->current_core->radio->txpower[2] = 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_aphy; + else + bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index d90f207b247..d3c2fc1df37 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1768,14 +1768,9 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) where REG is the max power as per the regulatory domain */ - /*TODO: Get desired_pwr from wx_handlers or the stack - limit_value(desired_pwr, 0, max_pwr); - */ - - desired_pwr = max_pwr; /* remove this when we have a real desired_pwr */ - + desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); + /* Check if we need to adjust the current power. */ pwr_adjust = desired_pwr - estimated_pwr; - radio_att_delta = -(pwr_adjust + 7) >> 3; baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index c1d788d50f4..bed7cfbe81d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -484,21 +484,40 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + struct bcm43xx_phyinfo *phy; unsigned long flags; int err = -ENODEV; + u16 maxpower; wx_enter(); + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + printk(PFX KERN_ERR "TX power not in dBm.\n"); + return -EOPNOTSUPP; + } + spin_lock_irqsave(&bcm->lock, flags); if (!bcm->initialized) goto out_unlock; - if (data->power.disabled != (!(bcm->current_core->radio->enabled))) { - if (data->power.disabled) + radio = bcm->current_core->radio; + phy = bcm->current_core->phy; + if (data->txpower.disabled != (!(radio->enabled))) { + if (data->txpower.disabled) bcm43xx_radio_turn_off(bcm); else bcm43xx_radio_turn_on(bcm); } - //TODO: set txpower. + if (data->txpower.value > 0) { + /* desired and maxpower dBm values are in Q5.2 */ + if (phy->type == BCM43xx_PHYTYPE_A) + maxpower = bcm->sprom.maxpower_aphy; + else + maxpower = bcm->sprom.maxpower_bgphy; + radio->txpower_desired = limit_value(data->txpower.value << 2, + 0, maxpower); + bcm43xx_phy_xmitpower(bcm); + } err = 0; out_unlock: @@ -513,18 +532,27 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; + int err = -ENODEV; wx_enter(); spin_lock_irqsave(&bcm->lock, flags); -//TODO data->power.value = ??? - data->power.fixed = 1; - data->power.flags = IW_TXPOW_DBM; - data->power.disabled = !(bcm->current_core->radio->enabled); + if (!bcm->initialized) + goto out_unlock; + radio = bcm->current_core->radio; + /* desired dBm value is in Q5.2 */ + data->txpower.value = radio->txpower_desired >> 2; + data->txpower.fixed = 1; + data->txpower.flags = IW_TXPOW_DBM; + data->txpower.disabled = !(radio->enabled); + + err = 0; +out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); - return 0; + return err; } static int bcm43xx_wx_set_retry(struct net_device *net_dev, -- cgit v1.2.3-70-g09d2 From 62b7f0dfab0508a45a93045d49eda26d5285188d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 17:36:46 +0100 Subject: [PATCH] bcm43xx: enable SPROM writing. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index bed7cfbe81d..6f6f19aed30 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -976,7 +976,7 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, printk("75%%"); else if (i % 2) printk("."); -//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); mdelay(20); } spromctl &= ~0x10; /* SPROM WRITE enable. */ -- cgit v1.2.3-70-g09d2 From 921e485f98b11656cdcc39a37605e116e34cb315 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 17:55:55 +0100 Subject: [PATCH] bcm43xx: heavily increase mac_suspend timeout. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 8e08c41f86d..4c4a2d71ca0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2473,16 +2473,13 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) & ~BCM43xx_SBF_MAC_ENABLED); bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - for (i = 1000; i > 0; i--) { + for (i = 100000; i; i--) { tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (tmp & BCM43xx_IRQ_READY) { - i = -1; - break; - } + if (tmp & BCM43xx_IRQ_READY) + return; udelay(10); } - if (!i) - printkl(KERN_ERR PFX "Failed to suspend mac!\n"); + printkl(KERN_ERR PFX "MAC suspend failed\n"); } void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, -- cgit v1.2.3-70-g09d2 From b5488beba8030b791e035c4da0122f98c42e355b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 18:00:30 +0100 Subject: [PATCH] bcm43xx: fix compiletime warning (phy_xmitpower) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 6f6f19aed30..d383337db99 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -40,6 +40,7 @@ #include "bcm43xx_wx.h" #include "bcm43xx_main.h" #include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" /* The WIRELESS_EXT version, which is implemented by this driver. */ -- cgit v1.2.3-70-g09d2 From 5c57807afcc28a6b8fb579ef2c79e49f0b688425 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 18:04:02 +0100 Subject: [PATCH] bcm43xx: remove WX debugging. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 68 ------------------------------- 1 file changed, 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index d383337db99..4c972cdc0a2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -46,18 +46,6 @@ /* The WIRELESS_EXT version, which is implemented by this driver. */ #define BCM43xx_WX_VERSION 18 - -/* Define to enable a printk on each wx handler function invocation */ -//#define BCM43xx_WX_DEBUG - - -#ifdef BCM43xx_WX_DEBUG -# define printk_wx printk -#else -# define printk_wx(x...) do { /* nothing */ } while (0) -#endif -#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__); - #define MAX_WX_STRING 80 @@ -73,8 +61,6 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); nr_80211 = bcm43xx_num_80211_cores(bcm); for (i = 0; i < nr_80211; i++) { @@ -127,8 +113,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, int freq; int err = 0; - wx_enter(); - if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -148,8 +132,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, } else bcm->current_core->radio->initial_channel = channel; spin_unlock_irqrestore(&bcm->lock, flags); - if (!err) - printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel); return err; } @@ -164,8 +146,6 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, int err = -ENODEV; u16 channel; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); channel = bcm->current_core->radio->channel; if (channel == 0xFF) { @@ -195,8 +175,6 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, unsigned long flags; int mode; - wx_enter(); - mode = data->mode; if (mode == IW_MODE_AUTO) mode = BCM43xx_INITIAL_IWMODE; @@ -217,8 +195,6 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->mode = bcm->ieee->iw_mode; spin_unlock_irqrestore(&bcm->lock, flags); @@ -231,7 +207,6 @@ static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -241,7 +216,6 @@ static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -257,8 +231,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, unsigned long flags; int i, j; - wx_enter(); - data->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -355,8 +327,6 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, unsigned long flags; size_t len; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); memcpy(bcm->nick, extra, len); @@ -375,8 +345,6 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, unsigned long flags; size_t len; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); len = strlen(bcm->nick) + 1; memcpy(extra, bcm->nick, len); @@ -396,8 +364,6 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (data->rts.disabled) { bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; @@ -422,8 +388,6 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->rts.value = bcm->rts_threshold; data->rts.fixed = 0; @@ -442,8 +406,6 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (data->frag.disabled) { bcm->ieee->fts = MAX_FRAG_THRESHOLD; @@ -468,8 +430,6 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->frag.value = bcm->ieee->fts; data->frag.fixed = 0; @@ -491,8 +451,6 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, int err = -ENODEV; u16 maxpower; - wx_enter(); - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { printk(PFX KERN_ERR "TX power not in dBm.\n"); return -EOPNOTSUPP; @@ -537,8 +495,6 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, unsigned long flags; int err = -ENODEV; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (!bcm->initialized) goto out_unlock; @@ -561,7 +517,6 @@ static int bcm43xx_wx_set_retry(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -571,7 +526,6 @@ static int bcm43xx_wx_get_retry(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -584,8 +538,6 @@ static int bcm43xx_wx_set_encoding(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); return err; @@ -599,8 +551,6 @@ static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); return err; @@ -614,8 +564,6 @@ static int bcm43xx_wx_get_encoding(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); return err; @@ -629,8 +577,6 @@ static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); return err; @@ -641,7 +587,6 @@ static int bcm43xx_wx_set_power(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -651,7 +596,6 @@ static int bcm43xx_wx_get_power(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -665,8 +609,6 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, unsigned long flags; int mode, err = 0; - wx_enter(); - mode = *((int *)extra); switch (mode) { case 0: @@ -717,8 +659,6 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, unsigned long flags; int mode; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); mode = bcm->current_core->radio->interfmode; spin_unlock_irqrestore(&bcm->lock, flags); @@ -750,8 +690,6 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - on = *((int *)extra); spin_lock_irqsave(&bcm->lock, flags); bcm->short_preamble = !!on; @@ -769,8 +707,6 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); on = bcm->short_preamble; spin_unlock_irqrestore(&bcm->lock, flags); @@ -793,8 +729,6 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - on = *((int *)extra); spin_lock_irqsave(&bcm->lock, flags); bcm->ieee->host_encrypt = !!on; @@ -815,8 +749,6 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); on = bcm->ieee->host_encrypt; spin_unlock_irqrestore(&bcm->lock, flags); -- cgit v1.2.3-70-g09d2 From 77db31ea4322f2dd12dc814d6664ae96517604c0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:47:44 +0100 Subject: [PATCH] bcm43xx: Partially fix PIO code. Add Kconfig option for PIO or DMA mode (or both). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 18 +- drivers/net/wireless/bcm43xx/Kconfig | 57 +++++ drivers/net/wireless/bcm43xx/Makefile | 6 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 29 ++- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 46 ++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 69 +++-- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 383 ++++++++++++++-------------- drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 78 +++++- 8 files changed, 438 insertions(+), 248 deletions(-) create mode 100644 drivers/net/wireless/bcm43xx/Kconfig (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 3b1363c9719..5c4d7b4ece5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -500,23 +500,7 @@ config PRISM54 will be called prism54.ko. source "drivers/net/wireless/hostap/Kconfig" - -config BCM43XX - tristate "Broadcom BCM43xx wireless support" - depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL - select FW_LOADER - ---help--- - This is an experimental driver for the Broadcom 43xx wireless chip, - found in the Apple Airport Extreme and various other devices. - -config BCM43XX_DEBUG - bool "Broadcom BCM43xx debugging (RECOMMENDED)" - depends on BCM43XX - default y - ---help--- - Broadcom 43xx debugging messages. - Say Y, because the driver is still very experimental and - this will help you get it running. +source "drivers/net/wireless/bcm43xx/Kconfig" # yes, this works even when no drivers are selected config NET_WIRELESS diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig new file mode 100644 index 00000000000..d8d23155ee3 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -0,0 +1,57 @@ +config BCM43XX + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL + select FW_LOADER + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + +config BCM43XX_DEBUG + bool "Broadcom BCM43xx debugging (RECOMMENDED)" + depends on BCM43XX + default y + ---help--- + Broadcom 43xx debugging messages. + Say Y, because the driver is still very experimental and + this will help you get it running. + +config BCM43XX_DMA + bool +config BCM43XX_PIO + bool + +choice + prompt "BCM43xx data transfer mode" + depends on BCM43XX + default BCM43XX_DMA_AND_PIO + +config BCM43XX_DMA_AND_PIO_MODE + bool "DMA + PIO" + select BCM43XX_DMA + select BCM43XX_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. + The actually used mode is selectable through the module + parameter "pio". If the module parameter is pio=0, DMA is used. + Otherwise PIO is used. DMA is default. + + If unsure, choose this option. + +config BCM43XX_DMA_MODE + bool "DMA (Direct Memory Access) only" + select BCM43XX_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config BCM43XX_PIO_MODE + bool "PIO (Programmed I/O) only" + select BCM43XX_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + Only use PIO, if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index e025e9f052b..c87c1525b39 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -1,9 +1,11 @@ obj-$(CONFIG_BCM43XX) += bcm43xx.o bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o -bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ +bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o +bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o + +bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ - bcm43xx_pio.o bcm43xx_ilt.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 981d563f573..3d8ac7e952c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -639,7 +639,7 @@ struct bcm43xx_private { u32 initialized:1, /* init_board() succeed */ was_initialized:1, /* for PCI suspend/resume. */ shutting_down:1, /* free_board() in progress */ - pio_mode:1, /* PIO (if true), or DMA (if false) used. */ + __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ @@ -749,6 +749,33 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) return ieee80211softmac_priv(dev); } + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return bcm->__using_pio; +} +#elif defined(CONFIG_BCM43XX_DMA) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 0; +} +#elif defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + + static inline int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 93e99d61f2e..88ad34dff2f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -94,6 +94,10 @@ #define BCM43xx_TXRESUME_PERCENT 50 + +#ifdef CONFIG_BCM43XX_DMA + + struct sk_buff; struct bcm43xx_private; struct bcm43xx_xmitstatus; @@ -172,4 +176,46 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb); void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); + +#else /* CONFIG_BCM43XX_DMA */ + + +static inline +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ +} + +#endif /* CONFIG_BCM43XX_DMA */ #endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4c4a2d71ca0..4e49da99818 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -62,10 +62,15 @@ MODULE_LICENSE("GPL"); extern char *nvram_get(char *name); #endif -/* Module parameters */ +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) static int modparam_pio; module_param_named(pio, modparam_pio, int, 0444); MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_BCM43XX_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_BCM43XX_PIO) +# define modparam_pio 1 +#endif static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); @@ -1528,7 +1533,8 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) { u32 flags = 0x00040000; - if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) { + if ((bcm43xx_core_enabled(bcm)) && + !bcm43xx_using_pio(bcm)) { //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? #ifndef CONFIG_BCM947XX /* reset all used DMA controllers. */ @@ -1635,7 +1641,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) } //TODO: There are more (unknown) flags to test. see bcm43xx_main.h - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_handle_xmitstatus(bcm, &stat); else bcm43xx_dma_handle_xmitstatus(bcm, &stat); @@ -1933,7 +1939,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue0); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); @@ -1941,7 +1947,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (likely(bcm->current_core->rev < 5)) { - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue3); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); @@ -1999,7 +2005,7 @@ void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) & 0x0001dc00; - if ((bcm->pio_mode) && + if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ @@ -2624,7 +2630,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) value32 |= 0x100000; //FIXME: What's this? Is this correct? bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - if (bcm->pio_mode) { + if (bcm43xx_using_pio(bcm)) { bcm43xx_write32(bcm, 0x0210, 0x00000100); bcm43xx_write32(bcm, 0x0230, 0x00000100); bcm43xx_write32(bcm, 0x0250, 0x00000100); @@ -3123,15 +3129,12 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) if (bcm->current_core->rev >= 5) bcm43xx_write16(bcm, 0x043C, 0x000C); - if (!bcm->pio_mode) { - err = bcm43xx_dma_init(bcm); - if (err) - goto err_chip_cleanup; - } else { + if (bcm43xx_using_pio(bcm)) err = bcm43xx_pio_init(bcm); - if (err) - goto err_chip_cleanup; - } + else + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; bcm43xx_write16(bcm, 0x0612, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); @@ -4001,8 +4004,8 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, { int err = -ENODEV; - if (bcm->pio_mode) - err = bcm43xx_pio_transfer_txb(bcm, txb); + if (bcm43xx_using_pio(bcm)) + err = bcm43xx_pio_tx(bcm, txb); else err = bcm43xx_dma_tx(bcm, txb); @@ -4158,10 +4161,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev) return 0; } -static void bcm43xx_init_private(struct bcm43xx_private *bcm, - struct net_device *net_dev, - struct pci_dev *pci_dev, - struct workqueue_struct *wq) +static int bcm43xx_init_private(struct bcm43xx_private *bcm, + struct net_device *net_dev, + struct pci_dev *pci_dev, + struct workqueue_struct *wq) { bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); @@ -4190,13 +4193,17 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, (unsigned long)bcm); tasklet_disable_nosync(&bcm->isr_tasklet); if (modparam_pio) { - bcm->pio_mode = 1; + bcm->__using_pio = 1; } else { - if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) { - bcm->pio_mode = 0; - } else { + if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) { +#ifdef CONFIG_BCM43XX_PIO printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); - bcm->pio_mode = 1; + bcm->__using_pio = 1; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Recompile the driver with PIO support, please.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ } } bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; @@ -4210,6 +4217,8 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); bcm->ieee->set_security = bcm43xx_ieee80211_set_security; bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; + + return 0; } static int __devinit bcm43xx_init_one(struct pci_dev *pdev, @@ -4261,7 +4270,9 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_free_netdev; } - bcm43xx_init_private(bcm, net_dev, pdev, wq); + err = bcm43xx_init_private(bcm, net_dev, pdev, wq); + if (err) + goto err_destroy_wq; pci_set_drvdata(pdev, net_dev); @@ -4325,7 +4336,9 @@ static void bcm43xx_chip_reset(void *_bcm) bcm43xx_free_board(bcm); bcm->firmware_norelease = 0; bcm43xx_detach_board(bcm); - bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + if (err) + goto failure; err = bcm43xx_attach_board(bcm); if (err) goto failure; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 9a55e9d0052..0bf4b3e26f9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -30,81 +30,88 @@ #include -static inline -u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, - u16 offset) +static void tx_start(struct bcm43xx_pioqueue *queue) { - return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_INIT); } -static inline -void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, - u16 offset, u16 value) +static void tx_octet(struct bcm43xx_pioqueue *queue, + u8 octet) { - bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + } } -static inline -void tx_start(struct bcm43xx_pioqueue *queue) +static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int *pos) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT); -} + const u8 *source; + unsigned int i = *pos; + u16 ret; -static inline -void tx_octet(struct bcm43xx_pioqueue *queue, - u8 octet) -{ - if (queue->bcm->current_core->rev < 3) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + if (i < sizeof(*txhdr)) { + source = (const u8 *)txhdr; } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + source = packet; + i -= sizeof(*txhdr); } + ret = le16_to_cpu( *((u16 *)(source + i)) ); + *pos += 2; + + return ret; } -static inline -void tx_data(struct bcm43xx_pioqueue *queue, - u8 *packet, - unsigned int octets) +static void tx_data(struct bcm43xx_pioqueue *queue, + struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int octets) { u16 data; unsigned int i = 0; - if (queue->bcm->current_core->rev < 3) { - data = be16_to_cpu( *((u16 *)packet) ); + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, &i); bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); - i += 2; } bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI); - for ( ; i < octets - 1; i += 2) { - data = be16_to_cpu( *((u16 *)(packet + i)) ); + BCM43xx_PIO_TXCTL_WRITELO | + BCM43xx_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, &i); bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); } if (octets % 2) - tx_octet(queue, packet[octets - 1]); + tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); } -static inline -void tx_complete(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb) +static void tx_complete(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb) { - u16 data; - - if (queue->bcm->current_core->rev < 3) { - data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) ); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + skb->data[skb->len - 1]); bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE); + BCM43xx_PIO_TXCTL_WRITEHI | + BCM43xx_PIO_TXCTL_COMPLETE); } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_COMPLETE); } } -static inline -u16 generate_cookie(struct bcm43xx_pioqueue *queue, - int packetindex) +static u16 generate_cookie(struct bcm43xx_pioqueue *queue, + int packetindex) { u16 cookie = 0x0000; @@ -113,8 +120,6 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, * for the packet index (in the cache). */ switch (queue->mmio_base) { - default: - assert(0); case BCM43xx_MMIO_PIO1_BASE: break; case BCM43xx_MMIO_PIO2_BASE: @@ -126,6 +131,8 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, case BCM43xx_MMIO_PIO4_BASE: cookie = 0x3000; break; + default: + assert(0); } assert(((u16)packetindex & 0xF000) == 0x0000); cookie |= (u16)packetindex; @@ -133,66 +140,75 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, return cookie; } -static inline +static struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, struct bcm43xx_pio_txpacket **packet) { + struct bcm43xx_pio *pio = bcm->current_core->pio; struct bcm43xx_pioqueue *queue = NULL; int packetindex; switch (cookie & 0xF000) { case 0x0000: - queue = bcm->current_core->pio->queue0; + queue = pio->queue0; break; case 0x1000: - queue = bcm->current_core->pio->queue1; + queue = pio->queue1; break; case 0x2000: - queue = bcm->current_core->pio->queue2; + queue = pio->queue2; break; case 0x3000: - queue = bcm->current_core->pio->queue3; + queue = pio->queue3; break; default: assert(0); } - packetindex = (cookie & 0x0FFF); assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); - *packet = queue->__tx_packets_cache + packetindex; + *packet = &(queue->tx_packets_cache[packetindex]); return queue; } -static inline -void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb, - struct bcm43xx_pio_txpacket *packet) +static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb, + struct bcm43xx_pio_txpacket *packet) { + struct bcm43xx_txhdr txhdr; unsigned int octets; assert(skb_shinfo(skb)->nr_frags == 0); - assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); - - __skb_push(skb, sizeof(struct bcm43xx_txhdr)); bcm43xx_generate_txhdr(queue->bcm, - (struct bcm43xx_txhdr *)skb->data, - skb->data + sizeof(struct bcm43xx_txhdr), - skb->len - sizeof(struct bcm43xx_txhdr), + &txhdr, skb->data, skb->len, (packet->xmitted_frags == 0), generate_cookie(queue, pio_txpacket_getindex(packet))); tx_start(queue); - octets = skb->len; - if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue. - octets -= 2; - tx_data(queue, (u8 *)skb->data, octets); + octets = skb->len + sizeof(txhdr); + if (queue->need_workarounds) + octets--; + tx_data(queue, &txhdr, (u8 *)skb->data, octets); tx_complete(queue, skb); } -static inline -int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) +static void free_txpacket(struct bcm43xx_pio_txpacket *packet, + int irq_context) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + + ieee80211_txb_free(packet->txb); + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; + + assert(queue->tx_devq_used >= packet->xmitted_octets); + assert(queue->tx_devq_packets >= packet->xmitted_frags); + queue->tx_devq_used -= packet->xmitted_octets; + queue->tx_devq_packets -= packet->xmitted_frags; +} + +static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) { struct bcm43xx_pioqueue *queue = packet->queue; struct ieee80211_txb *txb = packet->txb; @@ -204,12 +220,11 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) skb = txb->fragments[i]; octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); - assert(queue->tx_devq_size >= octets); assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); assert(queue->tx_devq_used <= queue->tx_devq_size); /* Check if there is sufficient free space on the device - * TX queue. If not, return and let the TX-work-handler + * TX queue. If not, return and let the TX tasklet * retry later. */ if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) @@ -234,28 +249,15 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) return 0; } -static void free_txpacket(struct bcm43xx_pio_txpacket *packet) +static void tx_tasklet(unsigned long d) { - struct bcm43xx_pioqueue *queue = packet->queue; - - ieee80211_txb_free(packet->txb); - - list_move(&packet->list, &packet->queue->txfree); - - assert(queue->tx_devq_used >= packet->xmitted_octets); - queue->tx_devq_used -= packet->xmitted_octets; - assert(queue->tx_devq_packets >= packet->xmitted_frags); - queue->tx_devq_packets -= packet->xmitted_frags; -} - -static void txwork_handler(void *d) -{ - struct bcm43xx_pioqueue *queue = d; + struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; + struct bcm43xx_private *bcm = queue->bcm; unsigned long flags; struct bcm43xx_pio_txpacket *packet, *tmp_packet; int err; - spin_lock_irqsave(&queue->txlock, flags); + spin_lock_irqsave(&bcm->lock, flags); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { assert(packet->xmitted_frags < packet->txb->nr_frags); if (packet->xmitted_frags == 0) { @@ -270,22 +272,22 @@ static void txwork_handler(void *d) skb = packet->txb->fragments[i]; if (unlikely(skb->len > queue->tx_devq_size)) { dprintkl(KERN_ERR PFX "PIO TX device queue too small. " - "Dropping packet...\n"); - free_txpacket(packet); + "Dropping packet.\n"); + free_txpacket(packet, 1); goto next_packet; } } } - /* Now try to transmit the packet. + /* Try to transmit the packet. * This may not completely succeed. */ err = pio_tx_packet(packet); if (err) break; -next_packet: + next_packet: continue; } - spin_unlock_irqrestore(&queue->txlock, flags); + spin_unlock_irqrestore(&bcm->lock, flags); } static void setup_txqueues(struct bcm43xx_pioqueue *queue) @@ -293,8 +295,9 @@ static void setup_txqueues(struct bcm43xx_pioqueue *queue) struct bcm43xx_pio_txpacket *packet; int i; + queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { - packet = queue->__tx_packets_cache + i; + packet = &(queue->tx_packets_cache[i]); packet->queue = queue; INIT_LIST_HEAD(&packet->list); @@ -311,19 +314,19 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, u32 value; u16 qsize; - queue = kmalloc(sizeof(*queue), GFP_KERNEL); + queue = kzalloc(sizeof(*queue), GFP_KERNEL); if (!queue) goto out; - memset(queue, 0, sizeof(*queue)); queue->bcm = bcm; queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (bcm->current_core->rev < 3); INIT_LIST_HEAD(&queue->txfree); INIT_LIST_HEAD(&queue->txqueue); INIT_LIST_HEAD(&queue->txrunning); - spin_lock_init(&queue->txlock); - INIT_WORK(&queue->txwork, txwork_handler, queue); + tasklet_init(&queue->txtask, tx_tasklet, + (unsigned long)queue); value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value |= BCM43xx_SBF_XFER_REG_BYTESWAP; @@ -331,7 +334,7 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); if (qsize <= BCM43xx_PIO_TXQADJUST) { - printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize); + printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); goto err_freequeue; } qsize -= BCM43xx_PIO_TXQADJUST; @@ -354,13 +357,12 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue) netif_tx_disable(queue->bcm->net_dev); assert(queue->bcm->shutting_down); - cancel_delayed_work(&queue->txwork); - flush_workqueue(queue->bcm->workqueue); + tasklet_disable(&queue->txtask); list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) - free_txpacket(packet); + free_txpacket(packet, 0); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) - free_txpacket(packet); + free_txpacket(packet, 0); } static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) @@ -374,40 +376,43 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3); - bcm->current_core->pio->queue3 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); - bcm->current_core->pio->queue2 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); - bcm->current_core->pio->queue1 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); - bcm->current_core->pio->queue0 = NULL; + struct bcm43xx_pio *pio = bcm->current_core->pio; + + bcm43xx_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; } int bcm43xx_pio_init(struct bcm43xx_private *bcm) { + struct bcm43xx_pio *pio = bcm->current_core->pio; struct bcm43xx_pioqueue *queue; int err = -ENOMEM; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); if (!queue) goto out; - bcm->current_core->pio->queue0 = queue; + pio->queue0 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); if (!queue) goto err_destroy0; - bcm->current_core->pio->queue1 = queue; + pio->queue1 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); if (!queue) goto err_destroy1; - bcm->current_core->pio->queue2 = queue; + pio->queue2 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); if (!queue) goto err_destroy2; - bcm->current_core->pio->queue3 = queue; + pio->queue3 = queue; if (bcm->current_core->rev < 3) bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; @@ -418,41 +423,38 @@ out: return err; err_destroy2: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); - bcm->current_core->pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; err_destroy1: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); - bcm->current_core->pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; err_destroy0: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); - bcm->current_core->pio->queue0 = NULL; + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; goto out; } -static inline -int pio_transfer_txb(struct bcm43xx_pioqueue *queue, - struct ieee80211_txb *txb) +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) { + struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1; struct bcm43xx_pio_txpacket *packet; - unsigned long flags; u16 tmp; - spin_lock_irqsave(&queue->txlock, flags); assert(!queue->tx_suspended); assert(!list_empty(&queue->txfree)); tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); - if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) { - spin_unlock_irqrestore(&queue->txlock, flags); + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) return -EBUSY; - } packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); - packet->txb = txb; - list_move_tail(&packet->list, &queue->txqueue); - packet->xmitted_octets = 0; packet->xmitted_frags = 0; + packet->xmitted_octets = 0; + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); /* Suspend TX, if we are out of packets in the "free" queue. */ if (unlikely(list_empty(&queue->txfree))) { @@ -460,69 +462,66 @@ int pio_transfer_txb(struct bcm43xx_pioqueue *queue, queue->tx_suspended = 1; } - spin_unlock_irqrestore(&queue->txlock, flags); - queue_work(queue->bcm->workqueue, &queue->txwork); + tasklet_schedule(&queue->txtask); return 0; } -int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return pio_transfer_txb(bcm->current_core->pio->queue1, txb); -} - -void fastcall -bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { struct bcm43xx_pioqueue *queue; struct bcm43xx_pio_txpacket *packet; - unsigned long flags; queue = parse_cookie(bcm, status->cookie, &packet); assert(queue); - spin_lock_irqsave(&queue->txlock, flags); - free_txpacket(packet); +//TODO +if (!queue) +return; + free_txpacket(packet, 1); if (unlikely(queue->tx_suspended)) { queue->tx_suspended = 0; netif_wake_queue(queue->bcm->net_dev); } - - /* If there are packets on the txqueue, - * start the work handler again. - */ - if (!list_empty(&queue->txqueue)) { - queue_work(queue->bcm->workqueue, - &queue->txwork); - } - spin_unlock_irqrestore(&queue->txlock, flags); + /* If there are packets on the txqueue, poke the tasklet. */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); } static void pio_rx_error(struct bcm43xx_pioqueue *queue, + int clear_buffers, const char *error) { - printk("PIO RX error: %s\n", error); - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); + int i; + + printkl("PIO RX error: %s\n", error); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_READY); + if (clear_buffers) { + assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + } + } } -void fastcall -bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) { u16 preamble[21] = { 0 }; struct bcm43xx_rxhdr *rxhdr; - u16 tmp; - u16 len; - int i, err; - int preamble_readwords; + u16 tmp, len, rxflags2; + int i, preamble_readwords; struct sk_buff *skb; +return; tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { - dprintkl(KERN_ERR PFX "PIO RX: No data available\n"); + dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. return; } - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_DATAAVAILABLE); for (i = 0; i < 10; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); @@ -534,13 +533,14 @@ bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) return; data_ready: +//FIXME: endianess in this function. len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); if (unlikely(len > 0x700)) { - pio_rx_error(queue, "len > 0x700"); + pio_rx_error(queue, 0, "len > 0x700"); return; } if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { - pio_rx_error(queue, "len == 0"); + pio_rx_error(queue, 0, "len == 0"); return; } preamble[0] = cpu_to_le16(len); @@ -550,28 +550,38 @@ data_ready: preamble_readwords = 18 / sizeof(u16); for (i = 0; i < preamble_readwords; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - preamble[i + 1] = cpu_to_be16(tmp); + preamble[i + 1] = cpu_to_be16(tmp);//FIXME? } rxhdr = (struct bcm43xx_rxhdr *)preamble; - if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { - pio_rx_error(queue, "invalid frame"); - if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) { - for (i = 0; i < 15; i++) - bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */ - } + rxflags2 = le16_to_cpu(rxhdr->flags2); + if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { + pio_rx_error(queue, + (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), + "invalid frame"); return; } -//FIXME -#if 0 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { - bcm43xx_rx_transmitstatus(queue->bcm, - (const struct bcm43xx_hwxmitstatus *)(preamble + 1)); + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw; + struct bcm43xx_xmitstatus stat; + + hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(queue->bcm, &stat); + bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); + return; } -#endif + skb = dev_alloc_skb(len); if (unlikely(!skb)) { - pio_rx_error(queue, "out of memory"); + pio_rx_error(queue, 1, "OOM"); return; } skb_put(skb, len); @@ -580,13 +590,14 @@ data_ready: *((u16 *)(skb->data + i)) = tmp; } if (len % 2) { - tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); skb->data[len - 1] = (tmp & 0x00FF); - skb->data[0] = (tmp & 0xFF00) >> 8; + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) + skb->data[0x20] = (tmp & 0xFF00) >> 8; + else + skb->data[0x1E] = (tmp & 0xFF00) >> 8; } - err = bcm43xx_rx(queue->bcm, skb, rxhdr); - if (unlikely(err)) - dev_kfree_skb_irq(skb); + bcm43xx_rx(queue->bcm, skb, rxhdr); } /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h index 71b92ee3416..970627bc176 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h @@ -3,9 +3,8 @@ #include "bcm43xx.h" +#include #include -#include -#include #include @@ -32,6 +31,10 @@ #define BCM43xx_PIO_MAXTXPACKETS 256 + +#ifdef CONFIG_BCM43XX_PIO + + struct bcm43xx_pioqueue; struct bcm43xx_xmitstatus; @@ -44,13 +47,14 @@ struct bcm43xx_pio_txpacket { u16 xmitted_octets; }; -#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) struct bcm43xx_pioqueue { struct bcm43xx_private *bcm; u16 mmio_base; - u8 tx_suspended:1; + u8 tx_suspended:1, + need_workarounds:1; /* Workarounds needed for core.rev < 3 */ /* Adjusted size of the device internal TX buffer. */ u16 tx_devq_size; @@ -62,6 +66,7 @@ struct bcm43xx_pioqueue { * be taken on incoming TX requests. */ struct list_head txfree; + unsigned int nr_txfree; /* Packets on the txqueue are queued, * but not completely written to the chip, yet. */ @@ -70,19 +75,64 @@ struct bcm43xx_pioqueue { * posted to the device. We are waiting for the txstatus. */ struct list_head txrunning; - /* Locking of the TX queues and the accounting. */ - spinlock_t txlock; - struct work_struct txwork; - struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; }; +static inline +u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, + u16 offset) +{ + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); +} + +static inline +void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, + u16 offset, u16 value) +{ + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); +} + + int bcm43xx_pio_init(struct bcm43xx_private *bcm); void bcm43xx_pio_free(struct bcm43xx_private *bcm); -int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb)); -void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status)); - -void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)); +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); + +#else /* CONFIG_BCM43XX_PIO */ + +static inline +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ +} + +#endif /* CONFIG_BCM43XX_PIO */ #endif /* BCM43xx_PIO_H_ */ -- cgit v1.2.3-70-g09d2 From 8bcab3f55982cf28310f2303bef741424ad0f563 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:52:10 +0100 Subject: [PATCH] bcm43xx: add a note that not all devices support PIO. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index d8d23155ee3..1d677c15b21 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -52,6 +52,11 @@ config BCM43XX_PIO_MODE Only include Programmed I/O (PIO). This reduces the size of the driver module, by omitting the DMA code. Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the 43xx series support PIO. + The 4306 (Apple Airport Extreme and others) supports PIO, while + the 4318 is known to _not_ support PIO. + Only use PIO, if DMA does not work for you. endchoice -- cgit v1.2.3-70-g09d2 From f1f566236dcc4cb57cfae89b539e19c1290e7f34 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:55:06 +0100 Subject: [PATCH] Apple Airport: Add Kconfig note that the bcm43xx driver has to be used for Airport Extreme cards. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5c4d7b4ece5..9c01fb26c8f 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -309,7 +309,10 @@ config APPLE_AIRPORT Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface + a non-standard interface. + + This driver does not support the Airport Extreme (802.11b/g). Use + the BCM43xx driver for Airport Extreme cards. config PLX_HERMES tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" -- cgit v1.2.3-70-g09d2 From dcfd720bd733544606b053e8e68b7419211ace72 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 20:25:55 +0100 Subject: [PATCH] bcm43xx: fix LED code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 88 +++++++++++++++++++---------- drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 11 +++- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 3 files changed, 68 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 455a0c743f7..8f550c1a92e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -35,12 +35,13 @@ static void bcm43xx_led_changestate(struct bcm43xx_led *led) { struct bcm43xx_private *bcm = led->bcm; const int index = bcm43xx_led_index(led); + const u16 mask = (1 << index); u16 ledctl; assert(index >= 0 && index < BCM43xx_NR_LEDS); assert(led->blink_interval); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - __change_bit(index, (unsigned long *)(&ledctl)); + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } @@ -61,6 +62,8 @@ static void bcm43xx_led_blink(unsigned long d) static void bcm43xx_led_blink_start(struct bcm43xx_led *led, unsigned long interval) { + if (led->blink_interval) + return; led->blink_interval = interval; bcm43xx_led_changestate(led); led->blink_timer.expires = jiffies + interval; @@ -91,6 +94,39 @@ static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } +static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, + struct bcm43xx_led *led, + int led_index) +{ + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the BCM43xx_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = BCM43xx_LED_ACTIVITY; + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = BCM43xx_LED_RADIO_ALL; + break; + case 1: + led->behaviour = BCM43xx_LED_RADIO_B; + if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = BCM43xx_LED_ASSOC; + break; + case 2: + led->behaviour = BCM43xx_LED_RADIO_A; + break; + case 3: + led->behaviour = BCM43xx_LED_OFF; + break; + default: + assert(0); + } +} + int bcm43xx_leds_init(struct bcm43xx_private *bcm) { struct bcm43xx_led *led; @@ -105,31 +141,12 @@ int bcm43xx_leds_init(struct bcm43xx_private *bcm) for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); led->bcm = bcm; - init_timer(&led->blink_timer); - led->blink_timer.data = (unsigned long)led; - led->blink_timer.function = bcm43xx_led_blink; + setup_timer(&led->blink_timer, + bcm43xx_led_blink, + (unsigned long)led); if (sprom[i] == 0xFF) { - /* SPROM information not set. */ - switch (i) { - case 0: - if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = BCM43xx_LED_RADIO_ALL; - else - led->behaviour = BCM43xx_LED_ACTIVITY; - break; - case 1: - led->behaviour = BCM43xx_LED_RADIO_B; - break; - case 2: - led->behaviour = BCM43xx_LED_RADIO_A; - break; - case 3: - led->behaviour = BCM43xx_LED_OFF; - break; - default: - assert(0); - } + bcm43xx_led_init_hardcoded(bcm, led, i); } else { led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); @@ -157,19 +174,19 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) struct bcm43xx_radioinfo *radio = bcm->current_core->radio; struct bcm43xx_phyinfo *phy = bcm->current_core->phy; const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; - int i, turn_on = 0; + int i, turn_on; unsigned long interval = 0; u16 ledctl; ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); - if (led->behaviour == BCM43xx_LED_INACTIVE) - continue; + turn_on = 0; switch (led->behaviour) { + case BCM43xx_LED_INACTIVE: + continue; case BCM43xx_LED_OFF: - turn_on = 0; break; case BCM43xx_LED_ON: turn_on = 1; @@ -189,7 +206,6 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) phy->type == BCM43xx_PHYTYPE_G)); break; case BCM43xx_LED_MODE_BG: - turn_on = 0; if (phy->type == BCM43xx_PHYTYPE_G && 1/*FIXME: using G rates.*/) turn_on = 1; @@ -222,12 +238,22 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) continue; case BCM43xx_LED_WEIRD: //TODO - turn_on = 0; break; case BCM43xx_LED_ASSOC: - if (1/*TODO: associated*/) + if (bcm->softmac->associated) turn_on = 1; break; +#ifdef CONFIG_BCM43XX_DEBUG + case BCM43xx_LED_TEST_BLINKSLOW: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW); + continue; + case BCM43xx_LED_TEST_BLINKMEDIUM: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + continue; + case BCM43xx_LED_TEST_BLINKFAST: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST); + continue; +#endif /* CONFIG_BCM43XX_DEBUG */ default: assert(0); }; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h index 489a2b1e906..6f18e2f95db 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -16,7 +16,7 @@ struct bcm43xx_led { #define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) /* Delay between state changes when blinking in jiffies */ -#define BCM43xx_LEDBLINK_SLOW (HZ / 2) +#define BCM43xx_LEDBLINK_SLOW (HZ / 1) #define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) #define BCM43xx_LEDBLINK_FAST (HZ / 8) @@ -37,6 +37,15 @@ enum { /* LED behaviour values */ BCM43xx_LED_WEIRD,//FIXME BCM43xx_LED_ASSOC, BCM43xx_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + BCM43xx_LED_TEST_BLINKSLOW, + BCM43xx_LED_TEST_BLINKMEDIUM, + BCM43xx_LED_TEST_BLINKFAST, }; int bcm43xx_leds_init(struct bcm43xx_private *bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4e49da99818..fbf931d4a13 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1943,7 +1943,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_pio_rx(bcm->current_core->pio->queue0); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); - activity = 1; + /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (likely(bcm->current_core->rev < 5)) { -- cgit v1.2.3-70-g09d2 From ab4977f881fc23cb02ef6f20d1e8ebbdcfef75ad Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 22:40:39 +0100 Subject: [PATCH] bcm43xx: rewrite and simplify the periodic task handling. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 13 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 194 ++++++++++------------------ 2 files changed, 73 insertions(+), 134 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 3d8ac7e952c..99b2e72281e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -418,7 +418,6 @@ enum { struct net_device; struct pci_dev; -struct workqueue_struct; struct bcm43xx_dmaring; struct bcm43xx_pioqueue; @@ -706,18 +705,10 @@ struct bcm43xx_private { /* Interrupt Service Routine tasklet (bottom-half) */ struct tasklet_struct isr_tasklet; - /* Custom driver work queue. */ - struct workqueue_struct *workqueue; /* Periodic tasks */ - struct work_struct periodic_work0; -#define BCM43xx_PERIODIC_0_DELAY (HZ * 15) - struct work_struct periodic_work1; -#define BCM43xx_PERIODIC_1_DELAY ((HZ * 60) + HZ / 2) - struct work_struct periodic_work2; -#define BCM43xx_PERIODIC_2_DELAY ((HZ * 120) + HZ) - struct work_struct periodic_work3; -#define BCM43xx_PERIODIC_3_DELAY ((HZ * 30) + HZ / 5) + struct timer_list periodic_tasks; + unsigned int periodic_state; struct work_struct restart_work; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index fbf931d4a13..18152b0b2dd 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2939,7 +2939,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) core->phy->minlowsigpos[1] = 0; spin_lock_init(&core->phy->lock); core->radio = &bcm->radio[i]; - core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; core->radio->channel = 0xFF; core->radio->initial_channel = 0xFF; core->radio->lofcal = 0xFFFF; @@ -3261,144 +3261,104 @@ static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) ieee80211softmac_start(bcm->net_dev); } -static void bcm43xx_periodic_work0_handler(void *d) +static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - //TODO: unsigned int aci_average; - - spin_lock_irqsave(&bcm->lock, flags); + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { - //FIXME: aci_average = bcm43xx_update_aci_average(bcm); - if (bcm->current_core->radio->aci_enable && bcm->current_core->radio->aci_wlan_automatic) { - bcm43xx_mac_suspend(bcm); - if (!bcm->current_core->radio->aci_enable && - 1 /*FIXME: We are not scanning? */) { - /*FIXME: First add bcm43xx_update_aci_average() before - * uncommenting this: */ - //if (bcm43xx_radio_aci_scan) - // bcm43xx_radio_set_interference_mitigation(bcm, - // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); - } else if (1/*FIXME*/) { - //if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) - // bcm43xx_radio_set_interference_mitigation(bcm, - // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); - } - bcm43xx_mac_enable(bcm); - } else if (bcm->current_core->radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { - if (bcm->current_core->phy->rev == 1) { - //FIXME: implement rev1 workaround - } - } - } - bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? - //TODO for APHY (temperature?) + if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) + return; - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, - BCM43xx_PERIODIC_0_DELAY); - } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_mac_suspend(bcm); + bcm43xx_phy_lo_g_measure(bcm); + bcm43xx_mac_enable(bcm); } -static void bcm43xx_periodic_work1_handler(void *d) +static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - - spin_lock_irqsave(&bcm->lock, flags); - bcm43xx_phy_lo_mark_all_unused(bcm); if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { bcm43xx_mac_suspend(bcm); bcm43xx_calc_nrssi_slope(bcm); bcm43xx_mac_enable(bcm); } - - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, - BCM43xx_PERIODIC_1_DELAY); - } - spin_unlock_irqrestore(&bcm->lock, flags); } -static void bcm43xx_periodic_work2_handler(void *d) +static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - - spin_lock_irqsave(&bcm->lock, flags); - - assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_G); - assert(bcm->current_core->phy->rev >= 2); + /* Update device statistics. */ + bcm43xx_calculate_link_quality(bcm); +} - bcm43xx_mac_suspend(bcm); - bcm43xx_phy_lo_g_measure(bcm); - bcm43xx_mac_enable(bcm); +static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, - BCM43xx_PERIODIC_2_DELAY); + if (phy->type == BCM43xx_PHYTYPE_G) { + //TODO: update_aci_moving_average + if (radio->aci_enable && radio->aci_wlan_automatic) { + bcm43xx_mac_suspend(bcm); + if (!radio->aci_enable && 1 /*TODO: not scanning? */) { + if (0 /*TODO: bunch of conditions*/) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } + } else if (1/*TODO*/) { + /* + if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_NONE); + } + */ + } + bcm43xx_mac_enable(bcm); + } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) } -static void bcm43xx_periodic_work3_handler(void *d) +static void bcm43xx_periodic_task_handler(unsigned long d) { - struct bcm43xx_private *bcm = d; + struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; unsigned long flags; + unsigned int state; spin_lock_irqsave(&bcm->lock, flags); - /* Update device statistics. */ - bcm43xx_calculate_link_quality(bcm); + assert(bcm->initialized); + state = bcm->periodic_state; + if (state % 8 == 0) + bcm43xx_periodic_every120sec(bcm); + if (state % 4 == 0) + bcm43xx_periodic_every60sec(bcm); + if (state % 2 == 0) + bcm43xx_periodic_every30sec(bcm); + bcm43xx_periodic_every15sec(bcm); + bcm->periodic_state = state + 1; + + mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, - BCM43xx_PERIODIC_3_DELAY); - } spin_unlock_irqrestore(&bcm->lock, flags); } -/* Delete all periodic tasks and make - * sure they are not running any longer - */ static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) { - cancel_delayed_work(&bcm->periodic_work0); - cancel_delayed_work(&bcm->periodic_work1); - cancel_delayed_work(&bcm->periodic_work2); - cancel_delayed_work(&bcm->periodic_work3); - flush_workqueue(bcm->workqueue); + del_timer_sync(&bcm->periodic_tasks); } -/* Setup all periodic tasks. */ static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { - INIT_WORK(&bcm->periodic_work0, bcm43xx_periodic_work0_handler, bcm); - INIT_WORK(&bcm->periodic_work1, bcm43xx_periodic_work1_handler, bcm); - INIT_WORK(&bcm->periodic_work2, bcm43xx_periodic_work2_handler, bcm); - INIT_WORK(&bcm->periodic_work3, bcm43xx_periodic_work3_handler, bcm); - - /* Periodic task 0: Delay ~15sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, - BCM43xx_PERIODIC_0_DELAY); - - /* Periodic task 1: Delay ~60sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, - BCM43xx_PERIODIC_1_DELAY); + struct timer_list *timer = &(bcm->periodic_tasks); - /* Periodic task 2: Delay ~120sec */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && - bcm->current_core->phy->rev >= 2) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, - BCM43xx_PERIODIC_2_DELAY); - } - - /* Periodic task 3: Delay ~30sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, - BCM43xx_PERIODIC_3_DELAY); + setup_timer(timer, + bcm43xx_periodic_task_handler, + (unsigned long)bcm); + timer->expires = jiffies; + add_timer(timer); } static void bcm43xx_security_init(struct bcm43xx_private *bcm) @@ -3414,13 +3374,13 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) int i, err; unsigned long flags; + bcm43xx_periodic_tasks_delete(bcm); + spin_lock_irqsave(&bcm->lock, flags); bcm->initialized = 0; bcm->shutting_down = 1; spin_unlock_irqrestore(&bcm->lock, flags); - bcm43xx_periodic_tasks_delete(bcm); - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) continue; @@ -4163,13 +4123,11 @@ static int bcm43xx_net_stop(struct net_device *net_dev) static int bcm43xx_init_private(struct bcm43xx_private *bcm, struct net_device *net_dev, - struct pci_dev *pci_dev, - struct workqueue_struct *wq) + struct pci_dev *pci_dev) { bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; - bcm->workqueue = wq; #ifdef DEBUG_ENABLE_MMIO_PRINT bcm43xx_mmioprint_initial(bcm, 1); @@ -4226,7 +4184,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, { struct net_device *net_dev; struct bcm43xx_private *bcm; - struct workqueue_struct *wq; int err; #ifdef CONFIG_BCM947XX @@ -4265,20 +4222,15 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); memset(bcm, 0, sizeof(*bcm)); - wq = create_workqueue(KBUILD_MODNAME "_wq"); - if (!wq) { - err = -ENOMEM; - goto err_free_netdev; - } - err = bcm43xx_init_private(bcm, net_dev, pdev, wq); + err = bcm43xx_init_private(bcm, net_dev, pdev); if (err) - goto err_destroy_wq; + goto err_free_netdev; pci_set_drvdata(pdev, net_dev); err = bcm43xx_attach_board(bcm); if (err) - goto err_destroy_wq; + goto err_free_netdev; err = register_netdev(net_dev); if (err) { @@ -4296,8 +4248,6 @@ out: err_detach_board: bcm43xx_detach_board(bcm); -err_destroy_wq: - destroy_workqueue(wq); err_free_netdev: free_ieee80211softmac(net_dev); goto out; @@ -4312,7 +4262,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) unregister_netdev(net_dev); bcm43xx_detach_board(bcm); assert(bcm->ucode == NULL); - destroy_workqueue(bcm->workqueue); free_ieee80211softmac(net_dev); } @@ -4324,7 +4273,6 @@ static void bcm43xx_chip_reset(void *_bcm) struct bcm43xx_private *bcm = _bcm; struct net_device *net_dev = bcm->net_dev; struct pci_dev *pci_dev = bcm->pci_dev; - struct workqueue_struct *wq = bcm->workqueue; int err; int was_initialized = bcm->initialized; @@ -4336,7 +4284,7 @@ static void bcm43xx_chip_reset(void *_bcm) bcm43xx_free_board(bcm); bcm->firmware_norelease = 0; bcm43xx_detach_board(bcm); - err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_init_private(bcm, net_dev, pci_dev); if (err) goto failure; err = bcm43xx_attach_board(bcm); @@ -4364,7 +4312,7 @@ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); - queue_work(bcm->workqueue, &bcm->restart_work); + schedule_work(&bcm->restart_work); } #ifdef CONFIG_PM -- cgit v1.2.3-70-g09d2 From 489423c8d0ba2b4311530502f7b5a331da9a60f9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Feb 2006 00:11:07 +0100 Subject: [PATCH] bcm43xx: Code cleanups. This removes various "inline" statements and reduces codesize. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 281 +++++++++++----------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 18 +- 3 files changed, 127 insertions(+), 181 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 99b2e72281e..848717513b5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -19,16 +19,17 @@ #define PFX KBUILD_MODNAME ": " -#define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 +#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50 #define BCM43xx_IRQWAIT_MAX_RETRIES 50 #define BCM43xx_IO_SIZE 8192 -#define BCM43xx_REG_ACTIVE_CORE 0x80 -/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ -#define BCM43xx_PCICFG_ICR 0x94 +/* Active Core PCI Configuration Register. */ +#define BCM43xx_PCICFG_ACTIVE_CORE 0x80 /* SPROM control register. */ #define BCM43xx_PCICFG_SPROMCTL 0x88 +/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ +#define BCM43xx_PCICFG_ICR 0x94 /* MMIO offsets */ #define BCM43xx_MMIO_DMA1_REASON 0x20 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 18152b0b2dd..3443bd3c23e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -119,40 +119,29 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); //#define DEBUG_ENABLE_PCILOG -static struct pci_device_id bcm43xx_pci_tbl[] = { - - /* Detailed list maintained at: - * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices - */ - -#ifdef CONFIG_BCM947XX - /* SB bus on BCM947xx */ - { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#endif - +/* Detailed list maintained at: + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices + */ + static struct pci_device_id bcm43xx_pci_tbl[] = { /* Broadcom 4303 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4307 802.11b */ + /* Broadcom 4307 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4318 802.11b/g */ + /* Broadcom 4318 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4306 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4306 802.11a */ + /* Broadcom 4306 802.11a */ // { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4309 802.11a/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 43XG 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* required last entry */ - { 0, }, +#ifdef CONFIG_BCM947XX + /* SB bus on BCM947xx */ + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { 0 }, }; MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); @@ -353,9 +342,8 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); } -static inline -u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, - const int ofdm_modulation) +static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, + const int ofdm_modulation) { u8 rate; @@ -412,8 +400,7 @@ u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, return rate; } -static inline -u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) { switch (bitrate) { case IEEE80211_CCK_RATE_1MB: @@ -429,8 +416,7 @@ u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) return 0; } -static inline -u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) { switch (bitrate) { case IEEE80211_OFDM_RATE_6MB: @@ -489,13 +475,12 @@ static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, //bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); } -void fastcall -bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) { const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; @@ -606,9 +591,8 @@ void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); } -static inline -void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, - u16 offset) +static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, + u16 offset) { const u8 zero_addr[ETH_ALEN] = { 0 }; @@ -634,8 +618,7 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); } -static inline -void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) +static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) @@ -644,14 +627,12 @@ void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); } -static inline -void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) +static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 9); } -static inline -void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) +static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 20); } @@ -744,6 +725,8 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; u32 radio_id; u16 manufact; u16 version; @@ -769,10 +752,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) version = (radio_id & 0x0FFFF000) >> 12; revision = (radio_id & 0xF0000000) >> 28; - dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", radio_id, manufact, version, revision); - switch (bcm->current_core->phy->type) { + switch (phy->type) { case BCM43xx_PHYTYPE_A: if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) goto err_unsupported_radio; @@ -787,25 +770,25 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) break; } - bcm->current_core->radio->manufact = manufact; - bcm->current_core->radio->version = version; - bcm->current_core->radio->revision = revision; + radio->manufact = manufact; + radio->version = version; + radio->revision = revision; /* Set default attenuation values. */ - bcm->current_core->radio->txpower[0] = 2; - bcm->current_core->radio->txpower[1] = 2; + radio->txpower[0] = 2; + radio->txpower[1] = 2; if (revision == 1) - bcm->current_core->radio->txpower[2] = 3; + radio->txpower[2] = 3; else - bcm->current_core->radio->txpower[2] = 0; + radio->txpower[2] = 0; if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) - bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_aphy; + radio->txpower_desired = bcm->sprom.maxpower_aphy; else bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) - bcm->current_core->radio->nrssi_lt[i] = i; + radio->nrssi_lt[i] = i; return 0; @@ -1155,6 +1138,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) */ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -1165,7 +1149,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; - switch (bcm->current_core->phy->type) { + switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; buffer[0] = 0xCC010200; @@ -1187,7 +1171,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x0568, 0x0000); bcm43xx_write16(bcm, 0x07C0, 0x0000); - bcm43xx_write16(bcm, 0x050C, ((bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); + bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); bcm43xx_write16(bcm, 0x0508, 0x0000); bcm43xx_write16(bcm, 0x050A, 0x0000); bcm43xx_write16(bcm, 0x054C, 0x0000); @@ -1324,25 +1308,6 @@ static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) dprintk(KERN_INFO PFX "Keys cleared\n"); } -/* Puts the index of the current core into user supplied core variable. - * This function reads the value from the device. - * Almost always you don't want to call this, but use bcm->current_core - */ -static inline -int _get_current_core(struct bcm43xx_private *bcm, int *core) -{ - int err; - - err = bcm43xx_pci_read_config32(bcm, BCM43xx_REG_ACTIVE_CORE, core); - if (unlikely(err)) { - dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE read failed!\n"); - return -ENODEV; - } - *core = (*core - 0x18000000) / 0x1000; - - return 0; -} - /* Lowlevel core-switch function. This is only to be used in * bcm43xx_switch_core() and bcm43xx_probe_cores() */ @@ -1350,63 +1315,57 @@ static int _switch_core(struct bcm43xx_private *bcm, int core) { int err; int attempts = 0; - int current_core = -1; + u32 current_core; assert(core >= 0); - - err = _get_current_core(bcm, ¤t_core); - if (unlikely(err)) - goto out; - - /* Write the computed value to the register. This doesn't always - succeed so we retry BCM43xx_SWITCH_CORE_MAX_RETRIES times */ - while (current_core != core) { - if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) { - err = -ENODEV; - printk(KERN_ERR PFX - "unable to switch to core %u, retried %i times\n", - core, attempts); - goto out; - } - err = bcm43xx_pci_write_config32(bcm, BCM43xx_REG_ACTIVE_CORE, + while (1) { + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, (core * 0x1000) + 0x18000000); - if (unlikely(err)) { - dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE write failed!\n"); - continue; - } - _get_current_core(bcm, ¤t_core); + if (unlikely(err)) + goto error; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, + ¤t_core); + if (unlikely(err)) + goto error; + current_core = (current_core - 0x18000000) / 0x1000; + if (current_core == core) + break; + + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) + goto error; + udelay(10); + } #ifdef CONFIG_BCM947XX - if (bcm->pci_dev->bus->number == 0) - bcm->current_core_offset = 0x1000 * core; - else - bcm->current_core_offset = 0; + if (bcm->pci_dev->bus->number == 0) + bcm->current_core_offset = 0x1000 * core; + else + bcm->current_core_offset = 0; #endif - } - assert(err == 0); -out: - return err; + return 0; +error: + printk(KERN_ERR PFX "Failed to switch to core %d\n", core); + return -ENODEV; } int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) { int err; - if (!new_core) + if (unlikely(!new_core)) return 0; - if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) return -ENODEV; if (bcm->current_core == new_core) return 0; err = _switch_core(bcm, new_core->index); - if (!err) + if (likely(!err)) bcm->current_core = new_core; return err; } -static inline int bcm43xx_core_enabled(struct bcm43xx_private *bcm) +static int bcm43xx_core_enabled(struct bcm43xx_private *bcm) { u32 value; @@ -1609,7 +1568,7 @@ out: return err; } -static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) +static void handle_irq_transmit_status(struct bcm43xx_private *bcm) { u32 v0, v1; u16 tmp; @@ -1648,7 +1607,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) } } -static inline void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) +static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) { bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); @@ -1672,7 +1631,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) bcm43xx_generate_noise_sample(bcm); } -static inline void handle_irq_noise(struct bcm43xx_private *bcm) +static void handle_irq_noise(struct bcm43xx_private *bcm) { struct bcm43xx_radioinfo *radio = bcm->current_core->radio; u16 tmp; @@ -1747,8 +1706,7 @@ generate_new: bcm43xx_generate_noise_sample(bcm); } -static inline -void handle_irq_ps(struct bcm43xx_private *bcm) +static void handle_irq_ps(struct bcm43xx_private *bcm) { if (bcm->ieee->iw_mode == IW_MODE_MASTER) { ///TODO: PS TBTT @@ -1761,8 +1719,7 @@ void handle_irq_ps(struct bcm43xx_private *bcm) //FIXME else set to false? } -static inline -void handle_irq_reg124(struct bcm43xx_private *bcm) +static void handle_irq_reg124(struct bcm43xx_private *bcm) { if (!bcm->reg124_set_0x4) return; @@ -1772,8 +1729,7 @@ void handle_irq_reg124(struct bcm43xx_private *bcm) //FIXME: reset reg124_set_0x4 to false? } -static inline -void handle_irq_pmq(struct bcm43xx_private *bcm) +static void handle_irq_pmq(struct bcm43xx_private *bcm) { u32 tmp; @@ -1829,8 +1785,7 @@ static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); } -static inline -void handle_irq_beacon(struct bcm43xx_private *bcm) +static void handle_irq_beacon(struct bcm43xx_private *bcm) { u32 status; @@ -1992,9 +1947,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) #undef bcmirq_print_reasons -static inline -void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, - u32 reason, u32 mask) +static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, + u32 reason, u32 mask) { bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) & 0x0001dc00; @@ -2340,7 +2294,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) SA_SHIRQ, KBUILD_MODNAME, bcm); if (res) { printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); - return -EFAULT; + return -ENODEV; } bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); @@ -2367,7 +2321,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) /* Switch to the core used to write the GPIO register. * This is either the ChipCommon, or the PCI core. */ -static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) +static int switch_to_gpio_core(struct bcm43xx_private *bcm) { int err; @@ -2379,13 +2333,13 @@ static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); if (err == -ENODEV) { err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (err == -ENODEV) { + if (unlikely(err == -ENODEV)) { printk(KERN_ERR PFX "gpio error: " "Neither ChipCommon nor PCI core available!\n"); return -ENODEV; - } else if (err != 0) + } else if (unlikely(err != 0)) return -ENODEV; - } else if (err != 0) + } else if (unlikely(err != 0)) return -ENODEV; return 0; @@ -2691,40 +2645,30 @@ err_release_fw: * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) { - int err = -ENODEV; u32 value; u32 shm_backup; shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) { - printk(KERN_ERR PFX "Error: SHM mismatch (1) validating chip\n"); - goto out; - } - + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) + goto error; bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) { - printk(KERN_ERR PFX "Error: SHM mismatch (2) validating chip\n"); - goto out; - } - + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) + goto error; bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - if ((value | 0x80000000) != 0x80000400) { - printk(KERN_ERR PFX "Error: Bad Status Bitfield while validating chip\n"); - goto out; - } + if ((value | 0x80000000) != 0x80000400) + goto error; value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (value != 0x00000000) { - printk(KERN_ERR PFX "Error: Bad interrupt reason code while validating chip\n"); - goto out; - } + if (value != 0x00000000) + goto error; - err = 0; -out: - return err; + return 0; +error: + printk(KERN_ERR PFX "Failed to validate the chipaccess\n"); + return -ENODEV; } static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) @@ -3172,9 +3116,9 @@ static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); } -static inline void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, - u32 address, - u32 data) +static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, + u32 address, + u32 data) { bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); @@ -3523,6 +3467,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm) static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; u16 value; u8 phy_version; u8 phy_type; @@ -3578,15 +3523,15 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) phy_rev); } - bcm->current_core->phy->version = phy_version; - bcm->current_core->phy->type = phy_type; - bcm->current_core->phy->rev = phy_rev; + phy->version = phy_version; + phy->type = phy_type; + phy->rev = phy_rev; if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, GFP_KERNEL); if (!p) return -ENOMEM; - bcm->current_core->phy->_lo_pairs = p; + phy->_lo_pairs = p; } return 0; @@ -3757,9 +3702,9 @@ err_pci_disable: goto out; } -static inline -s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, - int ofdm, int adjust_2053, int adjust_2050) +static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) { s32 tmp; @@ -3816,8 +3761,8 @@ s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, return (s8)tmp; } -static inline -s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) +static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi) { s8 ret; @@ -3843,9 +3788,9 @@ int bcm43xx_rx_packet(struct bcm43xx_private *bcm, return 0; } -int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) { struct bcm43xx_plcp_hdr4 *plcp; struct ieee80211_rx_stats stats; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 1d3eddd314b..298e24b4ab6 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -111,12 +111,12 @@ struct bcm43xx_txhdr { struct sk_buff; -void FASTCALL(bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie)); +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie); /* RX header as received from the hardware. */ struct bcm43xx_rxhdr { @@ -244,9 +244,9 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); -int FASTCALL(bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr)); +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr); void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode); -- cgit v1.2.3-70-g09d2 From ea0922b067a0863f9a4198740651fd47a22af7f1 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 14:09:20 +0100 Subject: [PATCH] bcm43xx: Move sprom lowlevel reading/writing to its own functions. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 93 ++++++++++++++++++++++++----- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 + drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 66 ++------------------ 3 files changed, 86 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 3443bd3c23e..bcbd009a533 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -916,13 +916,84 @@ u8 bcm43xx_sprom_crc(const u16 *sprom) return crc; } - -static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom) { int i; + u8 crc, expected_crc; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + /* CRC-8 check. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " + "(0x%02X, expected: 0x%02X)\n", + crc, expected_crc); + return -EINVAL; + } + + return 0; +} + +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) +{ + int i, err; + u8 crc, expected_crc; + u32 spromctl; + + /* CRC-8 validation of the input data. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); + return -EINVAL; + } + + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= 0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + /* We must burn lots of CPU cycles here, but that does not + * really matter as one does not write the SPROM every other minute... + */ + printk(KERN_INFO PFX "[ 0%%"); + mdelay(500); + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + if (i == 16) + printk("25%%"); + else if (i == 32) + printk("50%%"); + else if (i == 48) + printk("75%%"); + else if (i % 2) + printk("."); + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mdelay(20); + } + spromctl &= ~0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + mdelay(500); + printk("100%% ]\n"); + printk(KERN_INFO PFX "SPROM written.\n"); + bcm43xx_controller_restart(bcm, "SPROM update"); + + return 0; +err_ctlreg: + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return -ENODEV; +} + +static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) +{ u16 value; u16 *sprom; - u8 crc, expected_crc; #ifdef CONFIG_BCM947XX char *c; #endif @@ -930,7 +1001,7 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), GFP_KERNEL); if (!sprom) { - printk(KERN_ERR PFX "read_sprom OOM\n"); + printk(KERN_ERR PFX "sprom_extract OOM\n"); return -ENOMEM; } #ifdef CONFIG_BCM947XX @@ -953,17 +1024,7 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); #else - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) - sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); - - /* CRC-8 check. */ - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " - "(0x%02X, expected: 0x%02X)\n", - crc, expected_crc); - } + bcm43xx_sprom_read(bcm, sprom); #endif /* boardflags2 */ @@ -3632,7 +3693,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) goto err_chipset_detach; } - err = bcm43xx_read_sprom(bcm); + err = bcm43xx_sprom_extract(bcm); if (err) goto err_chipset_detach; err = bcm43xx_leds_init(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 298e24b4ab6..0c4bd08568c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -280,4 +280,7 @@ u8 bcm43xx_sprom_crc(const u16 *sprom); void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom); + #endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 4c972cdc0a2..df37d28996c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -782,7 +782,6 @@ static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) char tmp[5] = { 0 }; int cnt = 0; unsigned long parsed; - u8 crc, expected_crc; if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) return -EINVAL; @@ -793,13 +792,6 @@ static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) sprom[cnt++] = swab16((u16)parsed); } - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); - return -EINVAL; - } - return 0; } @@ -809,7 +801,7 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = -EPERM, i; + int err = -EPERM; u16 *sprom; unsigned long flags; @@ -828,13 +820,10 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, spin_unlock_irqrestore(&bcm->lock, flags); goto out_kfree; } - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) - sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + err = bcm43xx_sprom_read(bcm, sprom); spin_unlock_irqrestore(&bcm->lock, flags); - - data->data.length = sprom2hex(sprom, extra); - - err = 0; + if (!err) + data->data.length = sprom2hex(sprom, extra); out_kfree: kfree(sprom); out: @@ -852,8 +841,6 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, unsigned long flags; char *input; unsigned int len; - u32 spromctl; - int i; if (!capable(CAP_SYS_RAWIO)) goto out; @@ -878,50 +865,9 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, spin_lock_irqsave(&bcm->lock, flags); err = -ENODEV; - if (!bcm->initialized) { - spin_unlock_irqrestore(&bcm->lock, flags); - goto out_kfree; - } - - printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); - goto out_unlock; - } - spromctl |= 0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); - goto out_unlock; - } - /* We must burn lots of CPU cycles here, but that does not - * really matter as one does not write the SPROM every other minute... - */ - printk(KERN_INFO PFX "[ 0%%"); - mdelay(500); - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - if (i == 16) - printk("25%%"); - else if (i == 32) - printk("50%%"); - else if (i == 48) - printk("75%%"); - else if (i % 2) - printk("."); - bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); - mdelay(20); - } - spromctl &= ~0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + if (!bcm->initialized) goto out_unlock; - } - mdelay(500); - printk("100%% ]\n"); - printk(KERN_INFO PFX "SPROM written.\n"); - err = 0; + err = bcm43xx_sprom_write(bcm, sprom); out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); out_kfree: -- cgit v1.2.3-70-g09d2 From ad3f086c49aa682e493c935cda76f3850ee4a80e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 14:12:22 +0100 Subject: [PATCH] bcm43xx: make bcm43xx_sprom_crc() static. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index bcbd009a533..b4767e42e8f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -901,7 +901,7 @@ static inline u8 bcm43xx_crc8(u8 crc, u8 data) return t[crc ^ data]; } -u8 bcm43xx_sprom_crc(const u16 *sprom) +static u8 bcm43xx_sprom_crc(const u16 *sprom) { int word; u8 crc = 0xFF; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 0c4bd08568c..0a22e833915 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -276,8 +276,6 @@ int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm); -u8 bcm43xx_sprom_crc(const u16 *sprom); - void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); -- cgit v1.2.3-70-g09d2 From 10d8dd88dcc2c8ebe8ac7dcf75a2da7c9f9ee0f3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 22:08:48 +0100 Subject: [PATCH] bcm43xx: split the channel helper functions, so that they can be used without a valid running core. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 80 ++++++++++++++++++----------- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 12 +++-- 3 files changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index b4767e42e8f..6195c2a1516 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1169,7 +1169,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_a) { for (i = 0, channel = 0; channel < 201; channel++) { chan = &geo.a[i++]; - chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->freq = bcm43xx_channel_to_freq_a(channel); chan->channel = channel; } geo.a_channels = i; @@ -1177,7 +1177,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_bg) { for (i = 0, channel = 1; channel < 15; channel++) { chan = &geo.bg[i++]; - chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->freq = bcm43xx_channel_to_freq_bg(channel); chan->channel = channel; } geo.bg_channels = i; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 0a22e833915..7d696d257f7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -187,58 +187,78 @@ struct bcm43xx_xmitstatus_queue { /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline -u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, - int freq) +u8 bcm43xx_freq_to_channel_a(int freq) +{ + return ((freq - 5000) / 5); +} +static inline +u8 bcm43xx_freq_to_channel_bg(int freq) { u8 channel; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - channel = (freq - 5000) / 5; - } else { - if (freq == 2484) - channel = 14; - else - channel = (freq - 2407) / 5; - } + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; return channel; } +static inline +u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, + int freq) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_freq_to_channel_a(freq); + return bcm43xx_freq_to_channel_bg(freq); +} /* Lightweight function to convert a channel number to a frequency (in Mhz). */ static inline -int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, - u8 channel) +int bcm43xx_channel_to_freq_a(u8 channel) +{ + return (5000 + (5 * channel)); +} +static inline +int bcm43xx_channel_to_freq_bg(u8 channel) { int freq; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - freq = 5000 + (5 * channel); - } else { - if (channel == 14) - freq = 2484; - else - freq = 2407 + (5 * channel); - } + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); return freq; } +static inline +int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_channel_to_freq_a(channel); + return bcm43xx_channel_to_freq_bg(channel); +} /* Lightweight function to check if a channel number is valid. * Note that this does _NOT_ check for geographical restrictions! */ static inline +int bcm43xx_is_valid_channel_a(u8 channel) +{ + return (channel <= 200); +} +static inline +int bcm43xx_is_valid_channel_bg(u8 channel) +{ + return (channel >= 1 && channel <= 14); +} +static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, - u8 channel) + u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - if (channel <= 200) - return 1; - } else { - if (channel >= 1 && channel <= 14) - return 1; - } - - return 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_is_valid_channel_a(channel); + return bcm43xx_is_valid_channel_bg(channel); } void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index df37d28996c..aa2d9930c43 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -111,8 +111,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, unsigned long flags; u8 channel; int freq; - int err = 0; + int err = -EINVAL; + spin_lock_irqsave(&bcm->lock, flags); if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -121,16 +122,17 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, freq = data->freq.m; } if (!bcm43xx_is_valid_channel(bcm, channel)) - return -EINVAL; - - spin_lock_irqsave(&bcm->lock, flags); + goto out_unlock; if (bcm->initialized) { //ieee80211softmac_disassoc(softmac, $REASON); bcm43xx_mac_suspend(bcm); err = bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); - } else + } else { bcm->current_core->radio->initial_channel = channel; + err = 0; + } +out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); return err; -- cgit v1.2.3-70-g09d2 From 26533e7e292075df1daf94965a7f3f0d91bd08a8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 22:25:09 +0100 Subject: [PATCH] bcm43xx: remove old unused struct. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 7d696d257f7..d460393ed34 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -179,11 +179,6 @@ struct bcm43xx_xmitstatus { //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 -struct bcm43xx_xmitstatus_queue { - struct list_head list; - struct bcm43xx_hwxmitstatus status; -}; - /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline -- cgit v1.2.3-70-g09d2 From c4c3beb7d70ae9d1fe97b7b49bc5a10ad26c2b01 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 20 Feb 2006 22:48:55 +0100 Subject: [PATCH] bcm43xx: Fix Kconfig typo (transfer mode default) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 1d677c15b21..418465600a7 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -23,7 +23,7 @@ config BCM43XX_PIO choice prompt "BCM43xx data transfer mode" depends on BCM43XX - default BCM43XX_DMA_AND_PIO + default BCM43XX_DMA_AND_PIO_MODE config BCM43XX_DMA_AND_PIO_MODE bool "DMA + PIO" -- cgit v1.2.3-70-g09d2 From bf7b876043e6e1390b1234d740f4fd9af20b3b9e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 17:58:18 +0100 Subject: [PATCH] bcm43xx: Workaround init_board vs IRQ race. The proper fix for this is to move IRQ enabling to the end of init_board. But this is nontrivial and needs to be done with care. Stay with this cheap workaround for now. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6195c2a1516..57306a65840 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2079,12 +2079,19 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re bcm43xx_interrupt_ack(bcm, reason, mask); - /* disable all IRQs. They are enabled again in the bottom half. */ - bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - - /* save the reason code and call our bottom half. */ - bcm->irq_reason = reason; - tasklet_schedule(&bcm->isr_tasklet); + /* Only accept IRQs, if we are initialized properly. + * This avoids an RX race while initializing. + * We should probably not enable IRQs before we are initialized + * completely, but some careful work is needed to fix this. I think it + * is best to stay with this cheap workaround for now... . + */ + if (likely(bcm->initialized)) { + /* disable all IRQs. They are enabled again in the bottom half. */ + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + /* save the reason code and call our bottom half. */ + bcm->irq_reason = reason; + tasklet_schedule(&bcm->isr_tasklet); + } spin_unlock(&bcm->lock); -- cgit v1.2.3-70-g09d2 From cad2b31a76763d06048fb23a17b062acd5d46639 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 18:08:55 +0100 Subject: [PATCH] bcm43xx: move initialized = 1 to the end of init_board. Note that the periodic work has to be started with initialized==1 Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 57306a65840..4a7d88d2821 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3484,15 +3484,17 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); - spin_lock_irqsave(&bcm->lock, flags); - bcm->initialized = 1; - spin_unlock_irqrestore(&bcm->lock, flags); - if (bcm->current_core->radio->initial_channel != 0xFF) { bcm43xx_mac_suspend(bcm); bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); bcm43xx_mac_enable(bcm); } + + /* Initialization of the board is done. Flag it as such. */ + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_periodic_tasks_setup(bcm); assert(err == 0); -- cgit v1.2.3-70-g09d2 From 1d1a73ccdc618168f2a5c962aab250605c93e517 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 18:19:59 +0100 Subject: [PATCH] bcm43xx: add assert(bcm->initialized) to periodic_tasks_setup(). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4a7d88d2821..899c06fe0bf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3366,6 +3366,7 @@ static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { struct timer_list *timer = &(bcm->periodic_tasks); + assert(bcm->initialized); setup_timer(timer, bcm43xx_periodic_task_handler, (unsigned long)bcm); -- cgit v1.2.3-70-g09d2 From f398f02d12cdc372e16c5e86246b10acf7211abc Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 23 Feb 2006 21:15:39 +0100 Subject: [PATCH] bcm43xx: Move TX/RX related functions to its own file. Add basic RTS/CTS code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 1 + drivers/net/wireless/bcm43xx/bcm43xx.h | 23 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 430 +----------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 131 ------ drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 579 +++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_xmit.h | 156 +++++++ 9 files changed, 746 insertions(+), 577 deletions(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_xmit.h (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index c87c1525b39..2962b5f9e3e 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -8,4 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ + bcm43xx_xmit.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 848717513b5..21c75cae14b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -314,23 +314,6 @@ /* Initial default iw_mode */ #define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA -/* Values/Masks for the device TX header */ -#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 -#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 -#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 -#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 -#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 - -#define BCM43xx_TXHDRCTL_OFDM 0x0001 -#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 -#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 -#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 - -#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 -#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 -#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 -#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 - /* Bus type PCI. */ #define BCM43xx_BUSTYPE_PCI 0 /* Bus type Silicone Backplane Bus. */ @@ -952,4 +935,10 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) +/** Helpers to print MAC addresses. */ +#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ + ((u8*)(x))[2], ((u8*)(x))[3], \ + ((u8*)(x))[4], ((u8*)(x))[5] + #endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 5a7dc43cd67..0bae0be4be2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -37,6 +37,7 @@ #include "bcm43xx_debugfs.h" #include "bcm43xx_dma.h" #include "bcm43xx_pio.h" +#include "bcm43xx_xmit.h" #define REALLY_BIG_BUFFER_SIZE (1024*256) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index af5c27f9bfd..e20fbaf29e0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -32,6 +32,7 @@ #include "bcm43xx_main.h" #include "bcm43xx_debugfs.h" #include "bcm43xx_power.h" +#include "bcm43xx_xmit.h" #include #include diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 899c06fe0bf..f1ac9940f14 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -50,6 +50,7 @@ #include "bcm43xx_power.h" #include "bcm43xx_wx.h" #include "bcm43xx_ethtool.h" +#include "bcm43xx_xmit.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); @@ -342,234 +343,6 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); } -static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, - const int ofdm_modulation) -{ - u8 rate; - - if (ofdm_modulation) { - switch (plcp->raw[0] & 0xF) { - case 0xB: - rate = IEEE80211_OFDM_RATE_6MB; - break; - case 0xF: - rate = IEEE80211_OFDM_RATE_9MB; - break; - case 0xA: - rate = IEEE80211_OFDM_RATE_12MB; - break; - case 0xE: - rate = IEEE80211_OFDM_RATE_18MB; - break; - case 0x9: - rate = IEEE80211_OFDM_RATE_24MB; - break; - case 0xD: - rate = IEEE80211_OFDM_RATE_36MB; - break; - case 0x8: - rate = IEEE80211_OFDM_RATE_48MB; - break; - case 0xC: - rate = IEEE80211_OFDM_RATE_54MB; - break; - default: - rate = 0; - assert(0); - } - } else { - switch (plcp->raw[0]) { - case 0x0A: - rate = IEEE80211_CCK_RATE_1MB; - break; - case 0x14: - rate = IEEE80211_CCK_RATE_2MB; - break; - case 0x37: - rate = IEEE80211_CCK_RATE_5MB; - break; - case 0x6E: - rate = IEEE80211_CCK_RATE_11MB; - break; - default: - rate = 0; - assert(0); - } - } - - return rate; -} - -static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_CCK_RATE_1MB: - return 0x0A; - case IEEE80211_CCK_RATE_2MB: - return 0x14; - case IEEE80211_CCK_RATE_5MB: - return 0x37; - case IEEE80211_CCK_RATE_11MB: - return 0x6E; - } - assert(0); - return 0; -} - -static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_OFDM_RATE_6MB: - return 0xB; - case IEEE80211_OFDM_RATE_9MB: - return 0xF; - case IEEE80211_OFDM_RATE_12MB: - return 0xA; - case IEEE80211_OFDM_RATE_18MB: - return 0xE; - case IEEE80211_OFDM_RATE_24MB: - return 0x9; - case IEEE80211_OFDM_RATE_36MB: - return 0xD; - case IEEE80211_OFDM_RATE_48MB: - return 0x8; - case IEEE80211_OFDM_RATE_54MB: - return 0xC; - } - assert(0); - return 0; -} - -static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, - u16 octets, const u8 bitrate, - const int ofdm_modulation) -{ - __le32 *data = &(plcp->data); - __u8 *raw = plcp->raw; - - /* Account for hardware-appended FCS. */ - octets += IEEE80211_FCS_LEN; - - if (ofdm_modulation) { - *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); - assert(!(octets & 0xF000)); - *data |= (octets << 5); - *data = cpu_to_le32(*data); - } else { - u32 plen; - - plen = octets * 16 / bitrate; - if ((octets * 16 % bitrate) > 0) { - plen++; - if ((bitrate == IEEE80211_CCK_RATE_11MB) - && ((octets * 8 % 11) < 4)) { - raw[1] = 0x84; - } else - raw[1] = 0x04; - } else - raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); - raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); - } - -//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); -} - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) -{ - const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; - const struct ieee80211_security *secinfo = &bcm->ieee->sec; - u8 bitrate; - int ofdm_modulation; - u8 fallback_bitrate; - int fallback_ofdm_modulation; - u16 tmp; - u16 encrypt_frame; - - /* Now construct the TX header. */ - memset(txhdr, 0, sizeof(*txhdr)); - - //TODO: Some RTS/CTS stuff has to be done. - //TODO: Encryption stuff. - //TODO: others? - - bitrate = bcm->softmac->txrates.default_rate; - ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); - fallback_bitrate = bcm->softmac->txrates.default_fallback; - fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); - - /* Set Frame Control from 80211 header. */ - txhdr->frame_control = wireless_header->frame_ctl; - /* Copy address1 from 80211 header. */ - memcpy(txhdr->mac1, wireless_header->addr1, 6); - /* Set the fallback duration ID. */ - //FIXME: We use the original durid for now. - txhdr->fallback_dur_id = wireless_header->duration_id; - - /* Set the cookie (used as driver internal ID for the frame) */ - txhdr->cookie = cpu_to_le16(cookie); - - encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; - if (encrypt_frame && !bcm->ieee->host_encrypt) { - const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; - if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) { - dprintkl(KERN_ERR PFX "invalid packet with PROTECTED" - "flag set discarded"); - return; - } - memcpy(txhdr->wep_iv, hdr->payload, 4); - /* Hardware appends ICV. */ - fragment_len += 4; - } - - /* Generate the PLCP header and the fallback PLCP header. */ - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), - fragment_len, - bitrate, ofdm_modulation); - bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len, - fallback_bitrate, fallback_ofdm_modulation); - - /* Set the CONTROL field */ - tmp = 0; - if (ofdm_modulation) - tmp |= BCM43xx_TXHDRCTL_OFDM; - if (bcm->short_preamble) //FIXME: could be the other way around, please test - tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; - tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) - & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; - txhdr->control = cpu_to_le16(tmp); - - /* Set the FLAGS field */ - tmp = 0; - if (!is_multicast_ether_addr(wireless_header->addr1) && - !is_broadcast_ether_addr(wireless_header->addr1)) - tmp |= BCM43xx_TXHDRFLAG_EXPECTACK; - if (1 /* FIXME: PS poll?? */) - tmp |= 0x10; // FIXME: unknown meaning. - if (fallback_ofdm_modulation) - tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; - if (is_first_fragment) - tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; - txhdr->flags = cpu_to_le16(tmp); - - /* Set WSEC/RATE field */ - if (encrypt_frame && !bcm->ieee->host_encrypt) { - tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) - & BCM43xx_TXHDR_WSEC_ALGO_MASK; - tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) - & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; - txhdr->wsec_rate = cpu_to_le16(tmp); - } - -//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header"); -} - static void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, u16 offset, @@ -3773,207 +3546,6 @@ err_pci_disable: goto out; } -static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi, int ofdm, - int adjust_2053, int adjust_2050) -{ - s32 tmp; - - switch (bcm->current_core->radio->version) { - case 0x2050: - if (ofdm) { - tmp = in_rssi; - if (tmp > 127) - tmp -= 256; - tmp *= 73; - tmp /= 64; - if (adjust_2050) - tmp += 25; - else - tmp -= 3; - } else { - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - if (in_rssi > 63) - in_rssi = 63; - tmp = bcm->current_core->radio->nrssi_lt[in_rssi]; - tmp = 31 - tmp; - tmp *= -131; - tmp /= 128; - tmp -= 57; - } else { - tmp = in_rssi; - tmp = 31 - tmp; - tmp *= -149; - tmp /= 128; - tmp -= 68; - } - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && - adjust_2050) - tmp += 25; - } - break; - case 0x2060: - if (in_rssi > 127) - tmp = in_rssi - 256; - else - tmp = in_rssi; - break; - default: - tmp = in_rssi; - tmp -= 11; - tmp *= 103; - tmp /= 64; - if (adjust_2053) - tmp -= 109; - else - tmp -= 83; - } - - return (s8)tmp; -} - -static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi) -{ - s8 ret; - - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - //TODO: Incomplete specs. - ret = 0; - } else - ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); - - return ret; -} - -static inline -int bcm43xx_rx_packet(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct ieee80211_rx_stats *stats) -{ - int err; - - err = ieee80211_rx(bcm->ieee, skb, stats); - if (unlikely(err == 0)) - return -EINVAL; - return 0; -} - -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) -{ - struct bcm43xx_plcp_hdr4 *plcp; - struct ieee80211_rx_stats stats; - struct ieee80211_hdr_4addr *wlhdr; - u16 frame_ctl; - int is_packet_for_us = 0; - int err = -EINVAL; - const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); - const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); - const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); - const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); - - if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); - /* Skip two unknown bytes and the PLCP header. */ - skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); - } else { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); - /* Skip the PLCP header. */ - skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); - } - /* The SKB contains the PAYLOAD (wireless header + data) - * at this point. The FCS at the end is stripped. - */ - - memset(&stats, 0, sizeof(stats)); - stats.mac_time = le16_to_cpu(rxhdr->mactime); - stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, - !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), - !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); - stats.signal = rxhdr->signal_quality; //FIXME -//TODO stats.noise = - stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm); -//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); - stats.received_channel = bcm->current_core->radio->channel; -//TODO stats.control = - stats.mask = IEEE80211_STATMASK_SIGNAL | -//TODO IEEE80211_STATMASK_NOISE | - IEEE80211_STATMASK_RATE | - IEEE80211_STATMASK_RSSI; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) - stats.freq = IEEE80211_52GHZ_BAND; - else - stats.freq = IEEE80211_24GHZ_BAND; - stats.len = skb->len; - - bcm->stats.last_rx = jiffies; - if (bcm->ieee->iw_mode == IW_MODE_MONITOR) - return bcm43xx_rx_packet(bcm, skb, &stats); - - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - - switch (bcm->ieee->iw_mode) { - case IW_MODE_ADHOC: - if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC) - is_packet_for_us = 1; - break; - case IW_MODE_INFRA: - default: - /* When receiving multicast or broadcast packets, filter out - the packets we send ourself; we shouldn't see those */ - if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && - (is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC))) - is_packet_for_us = 1; - break; - } - - frame_ctl = le16_to_cpu(wlhdr->frame_ctl); - if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { - frame_ctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_ctl = cpu_to_le16(frame_ctl); - /* trim IV and ICV */ - /* FIXME: this must be done only for WEP encrypted packets */ - if (skb->len < 32) { - dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " - "set and length < 32)\n"); - return -EINVAL; - } else { - memmove(skb->data + 4, skb->data, 24); - skb_pull(skb, 4); - skb_trim(skb, skb->len - 4); - stats.len -= 8; - } - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - } - - switch (WLAN_FC_GET_TYPE(frame_ctl)) { - case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); - break; - case IEEE80211_FTYPE_DATA: - if (is_packet_for_us) - err = bcm43xx_rx_packet(bcm, skb, &stats); - break; - case IEEE80211_FTYPE_CTL: - break; - default: - assert(0); - return -EINVAL; - } - - return err; -} - /* Do the Hardware IO operations to send the txb */ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index d460393ed34..086136c3d01 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -52,134 +52,12 @@ static inline void e_aton(char *str, char *dest) } #endif - -#define _bcm43xx_declare_plcp_hdr(size) \ - struct bcm43xx_plcp_hdr##size { \ - union { \ - __le32 data; \ - __u8 raw[size]; \ - } __attribute__((__packed__)); \ - } __attribute__((__packed__)) - -/* struct bcm43xx_plcp_hdr4 */ -_bcm43xx_declare_plcp_hdr(4); -/* struct bcm430c_plcp_hdr6 */ -_bcm43xx_declare_plcp_hdr(6); - -#undef _bcm43xx_declare_plcp_hdr - - #define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] #define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) /* Magic helper macro to pad structures. Ignore those above. It's magic. */ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -/* Device specific TX header. To be prepended to TX frames. */ -struct bcm43xx_txhdr { - union { - struct { - u16 flags; - u16 wsec_rate; - u16 frame_control; - u16 unknown_zeroed_0; - u16 control; - unsigned char wep_iv[10]; - unsigned char unknown_wsec_tkip_data[3]; //FIXME - PAD_BYTES(3); - unsigned char mac1[6]; - u16 unknown_zeroed_1; - struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; - u16 rts_cts_dur_fallback; - struct bcm43xx_plcp_hdr4 fallback_plcp; - u16 fallback_dur_id; - PAD_BYTES(2); - u16 cookie; - u16 unknown_scb_stuff; //FIXME - struct bcm43xx_plcp_hdr6 rts_cts_plcp; - u16 rts_cts_frame_type; - u16 rts_cts_dur; - unsigned char rts_cts_mac1[6]; - unsigned char rts_cts_mac2[6]; - PAD_BYTES(2); - struct bcm43xx_plcp_hdr6 plcp; - } __attribute__((__packed__)); - - unsigned char raw[82]; - } __attribute__((__packed__)); -} __attribute__((__packed__)); - -struct sk_buff; - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie); - -/* RX header as received from the hardware. */ -struct bcm43xx_rxhdr { - /* Frame Length. Must be generated explicitely in PIO mode. */ - __le16 frame_length; - PAD_BYTES(2); - /* Flags field 1 */ - __le16 flags1; - u8 rssi; - u8 signal_quality; - PAD_BYTES(2); - /* Flags field 3 */ - __le16 flags3; - /* Flags field 2 */ - __le16 flags2; - /* Lower 16bits of the TSF at the time the frame started. */ - __le16 mactime; - PAD_BYTES(14); -} __attribute__((__packed__)); - -#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) -/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ -#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) -#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) - -#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) -#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) -/*FIXME: WEP related flags */ - -#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) - -/* Transmit Status as received from the hardware. */ -struct bcm43xx_hwxmitstatus { - PAD_BYTES(4); - __le16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - PAD_BYTES(2); - __le16 seq; - __le16 unknown; //FIXME -} __attribute__((__packed__)); - -/* Transmit Status in CPU byteorder. */ -struct bcm43xx_xmitstatus { - u16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - u16 seq; - u16 unknown; //FIXME -}; - -#define BCM43xx_TXSTAT_FLAG_ACK 0x01 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 -#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 - - /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline u8 bcm43xx_freq_to_channel_a(int freq) @@ -259,10 +137,6 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr); - void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode); @@ -283,11 +157,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); -int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val); -int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val); -int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val); -int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); - void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 0bf4b3e26f9..7b45fa1314c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -26,6 +26,7 @@ #include "bcm43xx.h" #include "bcm43xx_pio.h" #include "bcm43xx_main.h" +#include "bcm43xx_xmit.h" #include diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c new file mode 100644 index 00000000000..5ee572e79f6 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -0,0 +1,579 @@ +/* + + Broadcom BCM43xx wireless driver + + Transmission (TX/RX) related functions. + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_xmit.h" + +#include + + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return IEEE80211_CCK_RATE_1MB; + case 0x14: + return IEEE80211_CCK_RATE_2MB; + case 0x37: + return IEEE80211_CCK_RATE_5MB; + case 0x6E: + return IEEE80211_CCK_RATE_11MB; + } + assert(0); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return IEEE80211_OFDM_RATE_6MB; + case 0xF: + return IEEE80211_OFDM_RATE_9MB; + case 0xA: + return IEEE80211_OFDM_RATE_12MB; + case 0xE: + return IEEE80211_OFDM_RATE_18MB; + case 0x9: + return IEEE80211_OFDM_RATE_24MB; + case 0xD: + return IEEE80211_OFDM_RATE_36MB; + case 0x8: + return IEEE80211_OFDM_RATE_48MB; + case 0xC: + return IEEE80211_OFDM_RATE_54MB; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return 0x0A; + case IEEE80211_CCK_RATE_2MB: + return 0x14; + case IEEE80211_CCK_RATE_5MB: + return 0x37; + case IEEE80211_CCK_RATE_11MB: + return 0x6E; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_OFDM_RATE_6MB: + return 0xB; + case IEEE80211_OFDM_RATE_9MB: + return 0xF; + case IEEE80211_OFDM_RATE_12MB: + return 0xA; + case IEEE80211_OFDM_RATE_18MB: + return 0xE; + case IEEE80211_OFDM_RATE_24MB: + return 0x9; + case IEEE80211_OFDM_RATE_36MB: + return 0xD; + case IEEE80211_OFDM_RATE_48MB: + return 0x8; + case IEEE80211_OFDM_RATE_54MB: + return 0xC; + } + assert(0); + return 0; +} + +static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate, + const int ofdm_modulation) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (ofdm_modulation) { + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + assert(!(octets & 0xF000)); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == IEEE80211_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 bcm43xx_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_2MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_5MB: + return IEEE80211_CCK_RATE_2MB; + case IEEE80211_CCK_RATE_11MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_6MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_9MB: + return IEEE80211_OFDM_RATE_6MB; + case IEEE80211_OFDM_RATE_12MB: + return IEEE80211_OFDM_RATE_9MB; + case IEEE80211_OFDM_RATE_18MB: + return IEEE80211_OFDM_RATE_12MB; + case IEEE80211_OFDM_RATE_24MB: + return IEEE80211_OFDM_RATE_18MB; + case IEEE80211_OFDM_RATE_36MB: + return IEEE80211_OFDM_RATE_24MB; + case IEEE80211_OFDM_RATE_48MB: + return IEEE80211_OFDM_RATE_36MB; + case IEEE80211_OFDM_RATE_54MB: + return IEEE80211_OFDM_RATE_48MB; + } + assert(0); + return 0; +} + +static +__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, + u8 bitrate) +{ + const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); + __le16 duration_id = wireless_header->duration_id; + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_MGMT: + //TODO: Steal the code from ieee80211, once it is completed there. + break; + case IEEE80211_FTYPE_CTL: + /* Use the original duration/id. */ + break; + default: + assert(0); + } + + return duration_id; +} + +static inline +u16 ceiling_div(u16 dividend, u16 divisor) +{ + return ((dividend + divisor - 1) / divisor); +} + +static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, + struct bcm43xx_txhdr *txhdr, + u16 *flags, + u8 bitrate, + const struct ieee80211_hdr_4addr *wlhdr) +{ + u16 fctl; + u16 dur; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; + u8 *sa, *da; + u16 flen; + +//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); +//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), + flen, bitrate, + !ieee80211_is_cck_rate(bitrate)); + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), + flen, fallback_bitrate, + !ieee80211_is_cck_rate(fallback_bitrate)); + fctl = IEEE80211_FTYPE_CTL; + fctl |= IEEE80211_STYPE_RTS; + dur = le16_to_cpu(wlhdr->duration_id); +/*FIXME: should we test for dur==0 here and let it unmodified in this case? + * The following assert checks for this case... + */ +assert(dur); +/*FIXME: The duration calculation is not really correct. + * I am not 100% sure which bitrate to use. We use the RTS rate here, + * but this is likely to be wrong. + */ + if (phy->type == BCM43xx_PHYTYPE_A) { + /* Three times SIFS */ + dur += 16 * 3; + /* Add ACK duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + /* Add CTS duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + } else { + /* Three times SIFS */ + dur += 10 * 3; + /* Add ACK duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + /* Add CTS duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + } + + txhdr->rts_cts_frame_control = cpu_to_le16(fctl); + txhdr->rts_cts_dur = cpu_to_le16(dur); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); + memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! + memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); + + *flags |= BCM43xx_TXHDRFLAG_RTSCTS; + *flags |= BCM43xx_TXHDRFLAG_RTS; + if (ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; + if (fallback_ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; +} + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) +{ + const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; + const struct ieee80211_security *secinfo = &bcm->ieee->sec; + u8 bitrate; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; + u16 plcp_fragment_len = fragment_len; + u16 flags = 0; + u16 control = 0; + u16 wsec_rate = 0; + u16 encrypt_frame; + + /* Now construct the TX header. */ + memset(txhdr, 0, sizeof(*txhdr)); + + bitrate = bcm->softmac->txrates.default_rate; + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + /* Set Frame Control from 80211 header. */ + txhdr->frame_control = wireless_header->frame_ctl; + /* Copy address1 from 80211 header. */ + memcpy(txhdr->mac1, wireless_header->addr1, 6); + /* Set the fallback duration ID. */ + txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, + fallback_bitrate); + /* Set the cookie (used as driver internal ID for the frame) */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Hardware appends FCS. */ + plcp_fragment_len += IEEE80211_FCS_LEN; + + /* Hardware encryption. */ + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; + if (encrypt_frame && !bcm->ieee->host_encrypt) { + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; + memcpy(txhdr->wep_iv, hdr->payload, 4); + /* Hardware appends ICV. */ + plcp_fragment_len += 4; + + wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) + & BCM43xx_TXHDR_WSEC_ALGO_MASK; + wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; + } + + /* Generate the PLCP header and the fallback PLCP header. */ + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), + plcp_fragment_len, + bitrate, ofdm_modulation); + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, + fallback_bitrate, fallback_ofdm_modulation); + + /* Set the CONTROL field */ + if (ofdm_modulation) + control |= BCM43xx_TXHDRCTL_OFDM; + if (bcm->short_preamble) //FIXME: could be the other way around, please test + control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; + control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; + + /* Set the FLAGS field */ + if (!is_multicast_ether_addr(wireless_header->addr1) && + !is_broadcast_ether_addr(wireless_header->addr1)) + flags |= BCM43xx_TXHDRFLAG_EXPECTACK; + if (1 /* FIXME: PS poll?? */) + flags |= 0x10; // FIXME: unknown meaning. + if (fallback_ofdm_modulation) + flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; + if (is_first_fragment) + flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; + + /* Set WSEC/RATE field */ + wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) + & BCM43xx_TXHDR_RATE_MASK; + + /* Generate the RTS/CTS packet, if required. */ + /* FIXME: We should first try with CTS-to-self, + * if we are on 80211g. If we get too many + * failures (hidden nodes), we should switch back to RTS/CTS. + */ + if (0/*FIXME txctl->use_rts_cts*/) { + bcm43xx_generate_rts(phy, txhdr, &flags, + 0/*FIXME txctl->rts_cts_rate*/, + wireless_header); + } + + txhdr->flags = cpu_to_le16(flags); + txhdr->control = cpu_to_le16(control); + txhdr->wsec_rate = cpu_to_le16(wsec_rate); +} + +static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s32 tmp; + + switch (radio->version) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = radio->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == BCM43xx_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s8 ret; + + if (phy->type == BCM43xx_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); + + return ret; +} + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) +{ + struct bcm43xx_plcp_hdr4 *plcp; + struct ieee80211_rx_stats stats; + struct ieee80211_hdr_4addr *wlhdr; + u16 frame_ctl; + int is_packet_for_us = 0; + int err = -EINVAL; + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); + + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); + /* Skip two unknown bytes and the PLCP header. */ + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); + } else { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); + /* Skip the PLCP header. */ + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); + } + /* The SKB contains the PAYLOAD (wireless header + data) + * at this point. The FCS at the end is stripped. + */ + + memset(&stats, 0, sizeof(stats)); + stats.mac_time = le16_to_cpu(rxhdr->mactime); + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); + stats.signal = rxhdr->signal_quality; //FIXME +//TODO stats.noise = + if (is_ofdm) + stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); + else + stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); +//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); + stats.received_channel = bcm->current_core->radio->channel; +//TODO stats.control = + stats.mask = IEEE80211_STATMASK_SIGNAL | +//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_RATE | + IEEE80211_STATMASK_RSSI; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + stats.freq = IEEE80211_52GHZ_BAND; + else + stats.freq = IEEE80211_24GHZ_BAND; + stats.len = skb->len; + + bcm->stats.last_rx = jiffies; + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + return (err == 0) ? -EINVAL : 0; + } + + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + break; + case IW_MODE_INFRA: + default: + /* When receiving multicast or broadcast packets, filter out + the packets we send ourself; we shouldn't see those */ + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && + (is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC))) + is_packet_for_us = 1; + break; + } + + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); + /* trim IV and ICV */ + /* FIXME: this must be done only for WEP encrypted packets */ + if (skb->len < 32) { + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " + "set and length < 32)\n"); + return -EINVAL; + } else { + memmove(skb->data + 4, skb->data, 24); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + stats.len -= 8; + } + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + } + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); + break; + case IEEE80211_FTYPE_DATA: + if (is_packet_for_us) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + err = (err == 0) ? -EINVAL : 0; + } + break; + case IEEE80211_FTYPE_CTL: + break; + default: + assert(0); + return -EINVAL; + } + + return err; +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h new file mode 100644 index 00000000000..2aed19e35c7 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h @@ -0,0 +1,156 @@ +#ifndef BCM43xx_XMIT_H_ +#define BCM43xx_XMIT_H_ + +#include "bcm43xx_main.h" + + +#define _bcm43xx_declare_plcp_hdr(size) \ + struct bcm43xx_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct bcm43xx_plcp_hdr4 */ +_bcm43xx_declare_plcp_hdr(4); +/* struct bcm43xx_plcp_hdr6 */ +_bcm43xx_declare_plcp_hdr(6); + +#undef _bcm43xx_declare_plcp_hdr + +/* Device specific TX header. To be prepended to TX frames. */ +struct bcm43xx_txhdr { + union { + struct { + __le16 flags; + __le16 wsec_rate; + __le16 frame_control; + u16 unknown_zeroed_0; + __le16 control; + u8 wep_iv[10]; + u8 unknown_wsec_tkip_data[3]; //FIXME + PAD_BYTES(3); + u8 mac1[6]; + u16 unknown_zeroed_1; + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; + __le16 rts_cts_dur_fallback; + struct bcm43xx_plcp_hdr4 fallback_plcp; + __le16 fallback_dur_id; + PAD_BYTES(2); + __le16 cookie; + __le16 unknown_scb_stuff; //FIXME + struct bcm43xx_plcp_hdr6 rts_cts_plcp; + __le16 rts_cts_frame_control; + __le16 rts_cts_dur; + u8 rts_cts_mac1[6]; + u8 rts_cts_mac2[6]; + PAD_BYTES(2); + struct bcm43xx_plcp_hdr6 plcp; + } __attribute__((__packed__)); + u8 raw[82]; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + +/* Values/Masks for the device TX header */ +#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 +#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002 +#define BCM43xx_TXHDRFLAG_RTS 0x0004 +#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 +#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 +#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080 +#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 +#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200 +#define BCM43xx_TXHDRFLAG_CTS 0x0400 +#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 + +#define BCM43xx_TXHDRCTL_OFDM 0x0001 +#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 +#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 +#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 + +#define BCM43xx_TXHDR_RATE_MASK 0x0F00 +#define BCM43xx_TXHDR_RATE_SHIFT 8 +#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000 +#define BCM43xx_TXHDR_RTSRATE_SHIFT 12 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 +#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 +#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie); + +/* RX header as received from the hardware. */ +struct bcm43xx_rxhdr { + /* Frame Length. Must be generated explicitely in PIO mode. */ + __le16 frame_length; + PAD_BYTES(2); + /* Flags field 1 */ + __le16 flags1; + u8 rssi; + u8 signal_quality; + PAD_BYTES(2); + /* Flags field 3 */ + __le16 flags3; + /* Flags field 2 */ + __le16 flags2; + /* Lower 16bits of the TSF at the time the frame started. */ + __le16 mactime; + PAD_BYTES(14); +} __attribute__((__packed__)); + +#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) +/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ +#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) +#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) + +#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) +#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) +/*FIXME: WEP related flags */ + +#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) + +/* Transmit Status as received from the hardware. */ +struct bcm43xx_hwxmitstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + PAD_BYTES(2); + __le16 seq; + __le16 unknown; //FIXME +} __attribute__((__packed__)); + +/* Transmit Status in CPU byteorder. */ +struct bcm43xx_xmitstatus { + u16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + u16 seq; + u16 unknown; //FIXME +}; + +#define BCM43xx_TXSTAT_FLAG_ACK 0x01 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 +#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate); +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate); + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr); + +#endif /* BCM43xx_XMIT_H_ */ -- cgit v1.2.3-70-g09d2 From 367f899ac3b52cf4611cd291ec2bfbf774b15bc7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 28 Feb 2006 15:32:19 +0100 Subject: [PATCH] bcm43xx: Add sysfs attributes for device specific tunables. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 2 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 3 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 + drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 323 +++++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h | 25 +++ 5 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 2962b5f9e3e..bb5220c629d 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -8,5 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ - bcm43xx_xmit.o \ + bcm43xx_xmit.o bcm43xx_sysfs.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 21c75cae14b..fd9754b5295 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -15,6 +15,7 @@ #include "bcm43xx_debugfs.h" #include "bcm43xx_leds.h" +#include "bcm43xx_sysfs.h" #define PFX KBUILD_MODNAME ": " @@ -606,6 +607,8 @@ struct bcm43xx_key { }; struct bcm43xx_private { + struct bcm43xx_sysfs sysfs; + struct ieee80211_device *ieee; struct ieee80211softmac_device *softmac; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index f1ac9940f14..1fe2fa9856e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3160,6 +3160,8 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) int i, err; unsigned long flags; + bcm43xx_sysfs_unregister(bcm); + bcm43xx_periodic_tasks_delete(bcm); spin_lock_irqsave(&bcm->lock, flags); @@ -3270,6 +3272,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) spin_unlock_irqrestore(&bcm->lock, flags); bcm43xx_periodic_tasks_setup(bcm); + bcm43xx_sysfs_register(bcm); + //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... assert(err == 0); out: diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c new file mode 100644 index 00000000000..2d31737372f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -0,0 +1,323 @@ +/* + + Broadcom BCM43xx wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_sysfs.h" +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" + +#include + + +#define GENERIC_FILESIZE 64 + + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t)10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); +out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t bcm43xx_attr_sprom_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE); + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_read(bcm, sprom); + if (!err) { + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + buf[i * 2] = sprom[i] & 0x00FF; + buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + kfree(sprom); + + return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); +} + +static ssize_t bcm43xx_attr_sprom_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) + return -EINVAL; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + sprom[i] = buf[i * 2] & 0xFF; + sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; + } + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_write(bcm, sprom); + spin_unlock_irqrestore(&bcm->lock, flags); + kfree(sprom); + + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + switch (bcm->current_core->radio->interfmode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n"); + break; + default: + assert(0); + } + err = 0; + + spin_unlock_irqrestore(&bcm->lock, flags); + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + if (bcm->short_preamble) + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); + else + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); + + err = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + bcm->short_preamble = !!value; + + err = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + int err; + + assert(bcm->initialized); + + sysfs->attr_sprom.attr.name = "sprom"; + sysfs->attr_sprom.attr.owner = THIS_MODULE; + sysfs->attr_sprom.attr.mode = 0600; + sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; + sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; + err = device_create_file(dev, &sysfs->attr_sprom); + if (err) + goto out; + + sysfs->attr_interfmode.attr.name = "interference"; + sysfs->attr_interfmode.attr.owner = THIS_MODULE; + sysfs->attr_interfmode.attr.mode = 0600; + sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; + sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; + err = device_create_file(dev, &sysfs->attr_interfmode); + if (err) + goto err_remove_sprom; + + sysfs->attr_preamble.attr.name = "shortpreamble"; + sysfs->attr_preamble.attr.owner = THIS_MODULE; + sysfs->attr_preamble.attr.mode = 0600; + sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; + sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; + err = device_create_file(dev, &sysfs->attr_preamble); + if (err) + goto err_remove_interfmode; + +out: + return err; +err_remove_interfmode: + device_remove_file(dev, &sysfs->attr_interfmode); +err_remove_sprom: + device_remove_file(dev, &sysfs->attr_sprom); + goto out; +} + +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + + device_remove_file(dev, &sysfs->attr_preamble); + device_remove_file(dev, &sysfs->attr_interfmode); + device_remove_file(dev, &sysfs->attr_sprom); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h new file mode 100644 index 00000000000..57f14514e3e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h @@ -0,0 +1,25 @@ +#ifndef BCM43xx_SYSFS_H_ +#define BCM43xx_SYSFS_H_ + +#include + + +struct bcm43xx_sysfs { + struct device_attribute attr_sprom; + struct device_attribute attr_interfmode; + struct device_attribute attr_preamble; +}; + +#define devattr_to_bcm(attr, attr_name) ({ \ + struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ + __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ + __p = container_of(__s, struct bcm43xx_private, sysfs); \ + __p; \ + }) + +struct bcm43xx_private; + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_SYSFS_H_ */ -- cgit v1.2.3-70-g09d2 From 512a80916b8d04529c0915534c63529144f74e10 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 7 Mar 2006 01:37:51 +0100 Subject: [PATCH] bcm43xx: fix DMA TX skb freeing in case of fragmented packets. It seems to me that the today's wireless-2.6 git contains bcm43xx which does not free txb's correctly, if I understand it right. Consider a situation where a txb with two skb's is sent down. The dma_tx_fragment will save the pointer to meta->txb of the first fragment. If fragments are freed in order, ieee80211_txb_free frees both skb's when the first fragment is processed. This may result in reuse of the second skb's memory. This danger is rather remote, but it seems to me that the patch below not only fixes the problem, but also makes the code simpler, which is good, right? Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 44 ++++++------------------------ drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 4 --- 2 files changed, 8 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index e20fbaf29e0..0cd29284795 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -170,19 +170,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, addr, len, DMA_FROM_DEVICE); } -static inline -void mark_skb_mustfree(struct sk_buff *skb, - char mustfree) -{ - skb->cb[0] = mustfree; -} - -static inline -int skb_mustfree(struct sk_buff *skb) -{ - return (skb->cb[0] != 0); -} - /* Unmap and free a descriptor buffer. */ static inline void free_descriptor_buffer(struct bcm43xx_dmaring *ring, @@ -191,17 +178,11 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring, int irq_context) { assert(meta->skb); - if (skb_mustfree(meta->skb)) { - if (irq_context) - dev_kfree_skb_irq(meta->skb); - else - dev_kfree_skb(meta->skb); - } + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); meta->skb = NULL; - if (meta->txb) { - ieee80211_txb_free(meta->txb); - meta->txb = NULL; - } } static int alloc_ringmemory(struct bcm43xx_dmaring *ring) @@ -334,7 +315,6 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, meta->skb = skb; meta->dmaaddr = dmaaddr; skb->dev = ring->bcm->net_dev; - mark_skb_mustfree(skb, 1); desc_addr = (u32)(dmaaddr + ring->memoffset); desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & (u32)(ring->rx_buffersize - ring->frameoffset)); @@ -457,7 +437,6 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring) if (!meta->skb) { assert(ring->tx); - assert(!meta->txb); continue; } if (ring->tx) { @@ -726,7 +705,6 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, static int dma_tx_fragment(struct bcm43xx_dmaring *ring, struct sk_buff *skb, - struct ieee80211_txb *txb, u8 cur_frag) { int slot; @@ -741,11 +719,6 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, desc = ring->vbase + slot; meta = ring->meta + slot; - if (cur_frag == 0) { - /* Save the txb pointer for freeing in xmitstatus IRQ */ - meta->txb = txb; - } - /* Add a device specific TX header. */ assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); /* Reserve enough headroom for the device tx header. */ @@ -810,13 +783,12 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, for (i = 0; i < txb->nr_frags; i++) { skb = txb->fragments[i]; - /* We do not free the skb, as it is freed as - * part of the txb freeing. - */ - mark_skb_mustfree(skb, 0); - dma_tx_fragment(ring, skb, txb, i); + /* Take skb from ieee80211_txb_free */ + txb->fragments[i] = NULL; + dma_tx_fragment(ring, skb, i); //TODO: handle failure of dma_tx_fragment } + ieee80211_txb_free(txb); return 0; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 88ad34dff2f..cab8e2ba4c7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -119,10 +119,6 @@ struct bcm43xx_dmadesc_meta { struct sk_buff *skb; /* DMA base bus-address of the descriptor buffer. */ dma_addr_t dmaaddr; - /* Pointer to our txb (can be NULL). - * This should be freed in completion IRQ. - */ - struct ieee80211_txb *txb; }; struct bcm43xx_dmaring { -- cgit v1.2.3-70-g09d2 From 4d5a9e0eeb7ec928c6bd55db410f09ed3779bc2a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:15:02 +0100 Subject: [PATCH] bcm43xx: Set both, the DMAmask and the coherent DMAmask. This has a potential to fix the >1G bug. But I can not test that, yet. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 1fe2fa9856e..6da0beb0a93 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3717,6 +3717,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, struct net_device *net_dev, struct pci_dev *pci_dev) { + int err; + bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; @@ -3735,8 +3737,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; - if (modparam_bad_frames_preempt) - bcm->bad_frames_preempt = 1; + bcm->bad_frames_preempt = modparam_bad_frames_preempt; spin_lock_init(&bcm->lock); tasklet_init(&bcm->isr_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, @@ -3745,7 +3746,9 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, if (modparam_pio) { bcm->__using_pio = 1; } else { - if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) { + err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK); + err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK); + if (err) { #ifdef CONFIG_BCM43XX_PIO printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); bcm->__using_pio = 1; -- cgit v1.2.3-70-g09d2 From efccb647f486ff8174b4db0ab8145df8dd42ce6d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:39:14 +0100 Subject: [PATCH] bcm43xx: Abstract the locking mechanism. This is the starting point to make the driver out-of-order-MMIO-stores safe. There are more mmiowb() needed. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 20 ++++- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 26 +++--- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 75 +++++++++-------- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 25 +++--- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 112 ++++++++++++------------- 7 files changed, 142 insertions(+), 124 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index fd9754b5295..5f8c63fab83 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -619,7 +619,9 @@ struct bcm43xx_private { void __iomem *mmio_addr; unsigned int mmio_len; - spinlock_t lock; + /* Do not use the lock directly. Use the bcm43xx_lock* helper + * functions, to be MMIO-safe. */ + spinlock_t _lock; /* Driver status flags. */ u32 initialized:1, /* init_board() succeed */ @@ -721,6 +723,22 @@ struct bcm43xx_private { #endif }; +/* bcm43xx_(un)lock() protect struct bcm43xx_private. + * Note that _NO_ MMIO writes are allowed. If you want to + * write to the device through MMIO in the critical section, use + * the *_mmio lock functions. + * MMIO read-access is allowed, though. + */ +#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) +#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) +/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. + * MMIO write-access to the device is allowed. + * All MMIO writes are flushed on unlock, so it is guaranteed to not + * interfere with other threads writing MMIO registers. + */ +#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) +#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) + static inline struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 0bae0be4be2..bcfcebe2826 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -77,7 +77,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -124,7 +124,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, fappend("\n"); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -162,7 +162,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, unsigned long flags; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -172,7 +172,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -191,7 +191,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, u64 tsf; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -202,7 +202,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, (unsigned int)(tsf & 0xFFFFFFFFULL)); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -224,7 +224,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, res = -EFAULT; goto out_up; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); res = -EFAULT; @@ -239,7 +239,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, res = buf_size; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); out_up: up(&big_buffer_sem); return res; @@ -260,7 +260,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, int i, cnt, j = 0; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", BCM43xx_NR_LOGGED_XMITSTATUS); @@ -296,14 +296,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (*ppos == pos) { /* Done. Drop the copied data. */ e->xmitstatus_printing = 0; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); up(&big_buffer_sem); return res; } @@ -419,7 +419,7 @@ void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, struct bcm43xx_dfsentry *e; struct bcm43xx_xmitstatus *savedstatus; - /* This is protected by bcm->lock */ + /* This is protected by bcm->_lock */ e = bcm->dfsentry; assert(e); savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 8f550c1a92e..949555da5aa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d) struct bcm43xx_private *bcm = led->bcm; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (led->blink_interval) { bcm43xx_led_changestate(led); mod_timer(&led->blink_timer, jiffies + led->blink_interval); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void bcm43xx_led_blink_start(struct bcm43xx_led *led, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6da0beb0a93..b7192559833 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -482,14 +482,14 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old u32 old; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return -EBUSY; } old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); tasklet_disable(&bcm->isr_tasklet); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); if (oldstate) *oldstate = old; @@ -746,6 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) else if (i % 2) printk("."); bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mmiowb(); mdelay(20); } spromctl &= ~0x10; /* SPROM WRITE enable. */ @@ -1676,7 +1677,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) # define bcmirq_handled(irq) do { /* nothing */ } while (0) #endif /* CONFIG_BCM43XX_DEBUG*/ - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); reason = bcm->irq_reason; dma_reason[0] = bcm->dma_reason[0]; dma_reason[1] = bcm->dma_reason[1]; @@ -1776,7 +1777,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) if (!modparam_noleds) bcm43xx_leds_update(bcm, activity); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } #undef bcmirq_print_reasons @@ -1830,25 +1831,24 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, /* Interrupt handler top-half */ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) { + irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; u32 reason, mask; if (!bcm) return IRQ_NONE; - spin_lock(&bcm->lock); + spin_lock(&bcm->_lock); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) { /* irq not for us (shared irq) */ - spin_unlock(&bcm->lock); - return IRQ_NONE; + ret = IRQ_NONE; + goto out; } mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - if (!(reason & mask)) { - spin_unlock(&bcm->lock); - return IRQ_HANDLED; - } + if (!(reason & mask)) + goto out; bcm43xx_interrupt_ack(bcm, reason, mask); @@ -1866,9 +1866,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re tasklet_schedule(&bcm->isr_tasklet); } - spin_unlock(&bcm->lock); +out: + mmiowb(); + spin_unlock(&bcm->_lock); - return IRQ_HANDLED; + return ret; } static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) @@ -3112,7 +3114,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d) unsigned long flags; unsigned int state; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); state = bcm->periodic_state; @@ -3127,7 +3129,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d) mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) @@ -3164,10 +3166,10 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_periodic_tasks_delete(bcm); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 0; bcm->shutting_down = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) @@ -3182,9 +3184,9 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->shutting_down = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); } static int bcm43xx_init_board(struct bcm43xx_private *bcm) @@ -3196,10 +3198,10 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) might_sleep(); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 0; bcm->shutting_down = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); err = bcm43xx_pctl_set_crystal(bcm, 1); if (err) @@ -3267,9 +3269,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) } /* Initialization of the board is done. Flag it as such. */ - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); bcm43xx_periodic_tasks_setup(bcm); bcm43xx_sysfs_register(bcm); @@ -3570,11 +3572,11 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); bcm43xx_mac_suspend(bcm); bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } /* set_security() callback in struct ieee80211_device */ @@ -3587,9 +3589,9 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, int keyidx; dprintk(KERN_INFO PFX "set security called\n"); - - spin_lock_irqsave(&bcm->lock, flags); - + + bcm43xx_lock_mmio(bcm, flags); + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx] = sec->encode_alg[keyidx]; @@ -3651,7 +3653,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, } else bcm43xx_clear_keys(bcm); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } /* hard_start_xmit() callback in struct ieee80211_device */ @@ -3663,10 +3665,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, int err = -ENODEV; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (likely(bcm->initialized)) err = bcm43xx_tx(bcm, txb); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -3679,8 +3681,11 @@ static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_de static void bcm43xx_net_tx_timeout(struct net_device *net_dev) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + bcm43xx_lock_mmio(bcm, flags); bcm43xx_controller_restart(bcm, "TX timeout"); + bcm43xx_unlock_mmio(bcm, flags); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3738,7 +3743,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; bcm->bad_frames_preempt = modparam_bad_frames_preempt; - spin_lock_init(&bcm->lock); + spin_lock_init(&bcm->_lock); tasklet_init(&bcm->isr_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, (unsigned long)bcm); @@ -3921,11 +3926,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) dprintk(KERN_INFO PFX "Suspending...\n"); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->was_initialized = bcm->initialized; if (bcm->initialized) try_to_shutdown = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); netif_device_detach(net_dev); if (try_to_shutdown) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 7b45fa1314c..26dc6047d45 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -258,7 +258,7 @@ static void tx_tasklet(unsigned long d) struct bcm43xx_pio_txpacket *packet, *tmp_packet; int err; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { assert(packet->xmitted_frags < packet->txb->nr_frags); if (packet->xmitted_frags == 0) { @@ -288,7 +288,7 @@ static void tx_tasklet(unsigned long d) next_packet: continue; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void setup_txqueues(struct bcm43xx_pioqueue *queue) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 2d31737372f..713ec601c34 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -88,7 +88,7 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, GFP_KERNEL); if (!sprom) return -ENOMEM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_read(bcm, sprom); if (!err) { @@ -97,7 +97,7 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); kfree(sprom); return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); @@ -125,10 +125,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, sprom[i] = buf[i * 2] & 0xFF; sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_write(bcm, sprom); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); kfree(sprom); return err ? err : count; @@ -147,7 +147,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); switch (bcm->current_core->radio->interfmode) { @@ -165,7 +165,8 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, } err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); + return err ? err : count; } @@ -200,7 +201,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, return -EINVAL; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_radio_set_interference_mitigation(bcm, mode); @@ -209,7 +210,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, "supported by device\n"); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err ? err : count; } @@ -226,7 +227,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); if (bcm->short_preamble) @@ -235,7 +236,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err ? err : count; } @@ -255,13 +256,13 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, value = get_boolean(buf, count); if (value < 0) return value; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); bcm->short_preamble = !!value; err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err ? err : count; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index aa2d9930c43..208193851e8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -61,7 +61,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); nr_80211 = bcm43xx_num_80211_cores(bcm); for (i = 0; i < nr_80211; i++) { phy = bcm->phy + i; @@ -78,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, assert(0); } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); i = 0; if (have_a) { @@ -113,7 +113,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, int freq; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -133,7 +133,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, err = 0; } out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -148,7 +148,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, int err = -ENODEV; u16 channel; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); channel = bcm->current_core->radio->channel; if (channel == 0xFF) { assert(!bcm->initialized); @@ -163,7 +163,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -181,10 +181,10 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, if (mode == IW_MODE_AUTO) mode = BCM43xx_INITIAL_IWMODE; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm->ieee->iw_mode != mode) bcm43xx_set_iwmode(bcm, mode); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return 0; } @@ -197,9 +197,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->mode = bcm->ieee->iw_mode; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -269,7 +269,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); range->num_bitrates = 0; i = 0; @@ -315,7 +315,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, } range->num_frequency = j; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -329,11 +329,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, unsigned long flags; size_t len; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); memcpy(bcm->nick, extra, len); bcm->nick[len] = '\0'; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -347,12 +347,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, unsigned long flags; size_t len; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); len = strlen(bcm->nick) + 1; memcpy(extra, bcm->nick, len); data->data.length = (__u16)len; data->data.flags = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -366,7 +366,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (data->rts.disabled) { bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; err = 0; @@ -377,7 +377,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, err = 0; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -390,11 +390,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->rts.value = bcm->rts_threshold; data->rts.fixed = 0; data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -408,7 +408,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (data->frag.disabled) { bcm->ieee->fts = MAX_FRAG_THRESHOLD; err = 0; @@ -419,7 +419,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, err = 0; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -432,11 +432,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->frag.value = bcm->ieee->fts; data->frag.fixed = 0; data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -458,7 +458,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, return -EOPNOTSUPP; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) goto out_unlock; radio = bcm->current_core->radio; @@ -482,7 +482,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -497,7 +497,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, unsigned long flags; int err = -ENODEV; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (!bcm->initialized) goto out_unlock; radio = bcm->current_core->radio; @@ -509,7 +509,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -632,7 +632,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, return -EINVAL; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm->initialized) { err = bcm43xx_radio_set_interference_mitigation(bcm, mode); if (err) { @@ -647,7 +647,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, } else bcm->current_core->radio->interfmode = mode; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -661,9 +661,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, unsigned long flags; int mode; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); mode = bcm->current_core->radio->interfmode; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONE: @@ -693,9 +693,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, int on; on = *((int *)extra); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->short_preamble = !!on; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -709,9 +709,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); on = bcm->short_preamble; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); if (on) strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); @@ -732,13 +732,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, int on; on = *((int *)extra); - spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_lock(bcm, flags); bcm->ieee->host_encrypt = !!on; bcm->ieee->host_decrypt = !!on; bcm->ieee->host_build_iv = !on; - - spin_unlock_irqrestore(&bcm->lock, flags); - + bcm43xx_unlock(bcm, flags); + return 0; } @@ -750,17 +750,17 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; int on; - - spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_lock(bcm, flags); on = bcm->ieee->host_encrypt; - spin_unlock_irqrestore(&bcm->lock, flags); - + bcm43xx_unlock(bcm, flags); + if (on) strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); else strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); data->data.length = strlen(extra + 1); - + return 0; } @@ -816,17 +816,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, if (!sprom) goto out; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); err = -ENODEV; - if (!bcm->initialized) { - spin_unlock_irqrestore(&bcm->lock, flags); - goto out_kfree; - } - err = bcm43xx_sprom_read(bcm, sprom); - spin_unlock_irqrestore(&bcm->lock, flags); + if (bcm->initialized) + err = bcm43xx_sprom_read(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); if (!err) data->data.length = sprom2hex(sprom, extra); -out_kfree: kfree(sprom); out: return err; @@ -865,13 +861,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, if (err) goto out_kfree; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); err = -ENODEV; - if (!bcm->initialized) - goto out_unlock; - err = bcm43xx_sprom_write(bcm, sprom); -out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + if (bcm->initialized) + err = bcm43xx_sprom_write(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); out_kfree: kfree(sprom); out: -- cgit v1.2.3-70-g09d2 From 7ce942d0ff5df145831631f4df391c7207e676bb Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:43:06 +0100 Subject: [PATCH] bcm43xx: Remove the mmio access printing facility overhead. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 101 ++-------------------------- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 35 ---------- 2 files changed, 6 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 5f8c63fab83..29c95b07122 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -718,8 +718,6 @@ struct bcm43xx_private { /* Debugging stuff follows. */ #ifdef CONFIG_BCM43XX_DEBUG struct bcm43xx_dfsentry *dfsentry; - atomic_t mmio_print_cnt; - atomic_t pcicfg_print_cnt; #endif }; @@ -805,141 +803,54 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, } -/* MMIO read/write functions. Debug and non-debug variants. */ -#ifdef CONFIG_BCM43XX_DEBUG - static inline u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) { - u16 value; - - value = ioread16(bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "ioread16 offset: 0x%04x, value: 0x%04x\n", - offset, value); - } - - return value; + return ioread16(bcm->mmio_addr + core_offset(bcm) + offset); } static inline void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) { iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "iowrite16 offset: 0x%04x, value: 0x%04x\n", - offset, value); - } } static inline u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) { - u32 value; - - value = ioread32(bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "ioread32 offset: 0x%04x, value: 0x%08x\n", - offset, value); - } - - return value; + return ioread32(bcm->mmio_addr + core_offset(bcm) + offset); } static inline void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) { iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "iowrite32 offset: 0x%04x, value: 0x%08x\n", - offset, value); - } } static inline int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) { - int err; - - err = pci_read_config_word(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciread16 offset: 0x%08x, value: 0x%04x, err: %d\n", - offset, *value, err); - } - - return err; + return pci_read_config_word(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) { - int err; - - err = pci_read_config_dword(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciread32 offset: 0x%08x, value: 0x%08x, err: %d\n", - offset, *value, err); - } - - return err; + return pci_read_config_dword(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) { - int err; - - err = pci_write_config_word(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciwrite16 offset: 0x%08x, value: 0x%04x, err: %d\n", - offset, value, err); - } - - return err; + return pci_write_config_word(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) { - int err; - - err = pci_write_config_dword(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciwrite32 offset: 0x%08x, value: 0x%08x, err: %d\n", - offset, value, err); - } - - return err; + return pci_write_config_dword(bcm->pci_dev, offset, value); } -#define bcm43xx_mmioprint_initial(bcm, value) atomic_set(&(bcm)->mmio_print_cnt, (value)) -#define bcm43xx_mmioprint_enable(bcm) atomic_inc(&(bcm)->mmio_print_cnt) -#define bcm43xx_mmioprint_disable(bcm) atomic_dec(&(bcm)->mmio_print_cnt) -#define bcm43xx_pciprint_initial(bcm, value) atomic_set(&(bcm)->pcicfg_print_cnt, (value)) -#define bcm43xx_pciprint_enable(bcm) atomic_inc(&(bcm)->pcicfg_print_cnt) -#define bcm43xx_pciprint_disable(bcm) atomic_dec(&(bcm)->pcicfg_print_cnt) - -#else /* CONFIG_BCM43XX_DEBUG*/ - -#define bcm43xx_read16(bcm, offset) ioread16((bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_write16(bcm, offset, value) iowrite16((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_read32(bcm, offset) ioread32((bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_write32(bcm, offset, value) iowrite32((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_pci_read_config16(bcm, o, v) pci_read_config_word((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_read_config32(bcm, o, v) pci_read_config_dword((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_write_config16(bcm, o, v) pci_write_config_word((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_write_config32(bcm, o, v) pci_write_config_dword((bcm)->pci_dev, (o), (v)) - -#define bcm43xx_mmioprint_initial(x, y) do { /* nothing */ } while (0) -#define bcm43xx_mmioprint_enable(x) do { /* nothing */ } while (0) -#define bcm43xx_mmioprint_disable(x) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_initial(bcm, value) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_enable(bcm) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_disable(bcm) do { /* nothing */ } while (0) - -#endif /* CONFIG_BCM43XX_DEBUG*/ - - /** Limit a value between two limits */ #ifdef limit_value # undef limit_value diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index b7192559833..f3cef345c8f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2018,12 +2018,6 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) const u32 *data; unsigned int i, len; -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_enable(bcm); -#else - bcm43xx_mmioprint_disable(bcm); -#endif - /* Upload Microcode. */ data = (u32 *)(bcm->ucode->data); len = bcm->ucode->size / sizeof(u32); @@ -2045,12 +2039,6 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) be32_to_cpu(data[i])); udelay(10); } - -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_disable(bcm); -#else - bcm43xx_mmioprint_enable(bcm); -#endif } static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, @@ -2090,12 +2078,6 @@ static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) { int err; -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_enable(bcm); -#else - bcm43xx_mmioprint_disable(bcm); -#endif - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, bcm->initvals0->size / sizeof(struct bcm43xx_initval)); if (err) @@ -2106,13 +2088,7 @@ static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) if (err) goto out; } - out: -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_disable(bcm); -#else - bcm43xx_mmioprint_enable(bcm); -#endif return err; } @@ -3728,17 +3704,6 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; -#ifdef DEBUG_ENABLE_MMIO_PRINT - bcm43xx_mmioprint_initial(bcm, 1); -#else - bcm43xx_mmioprint_initial(bcm, 0); -#endif -#ifdef DEBUG_ENABLE_PCILOG - bcm43xx_pciprint_initial(bcm, 1); -#else - bcm43xx_pciprint_initial(bcm, 0); -#endif - bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; -- cgit v1.2.3-70-g09d2 From 73733847beead47dc31b1f8e1532e5eea9f8ddd3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Mar 2006 19:44:29 +0100 Subject: [PATCH] bcm43xx: fix some stuff, add a few missing mmiowb(), remove dead code. This may workaround the XMIT ERRORs some people are getting. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 23 +--- drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 42 +----- drivers/net/wireless/bcm43xx/bcm43xx_ilt.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 76 +++++++---- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 187 ++++++++++++++------------- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 20 +-- 6 files changed, 167 insertions(+), 187 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index cab8e2ba4c7..c07e34689be 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -9,27 +9,10 @@ /* DMA-Interrupt reasons. */ -/*TODO: add the missing ones. */ -#define BCM43xx_DMAIRQ_ERR0 (1 << 10) -#define BCM43xx_DMAIRQ_ERR1 (1 << 11) -#define BCM43xx_DMAIRQ_ERR2 (1 << 12) -#define BCM43xx_DMAIRQ_ERR3 (1 << 13) -#define BCM43xx_DMAIRQ_ERR4 (1 << 14) -#define BCM43xx_DMAIRQ_ERR5 (1 << 15) +#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) #define BCM43xx_DMAIRQ_RX_DONE (1 << 16) -/* helpers */ -#define BCM43xx_DMAIRQ_ANYERR (BCM43xx_DMAIRQ_ERR0 | \ - BCM43xx_DMAIRQ_ERR1 | \ - BCM43xx_DMAIRQ_ERR2 | \ - BCM43xx_DMAIRQ_ERR3 | \ - BCM43xx_DMAIRQ_ERR4 | \ - BCM43xx_DMAIRQ_ERR5) -#define BCM43xx_DMAIRQ_FATALERR (BCM43xx_DMAIRQ_ERR0 | \ - BCM43xx_DMAIRQ_ERR1 | \ - BCM43xx_DMAIRQ_ERR2 | \ - BCM43xx_DMAIRQ_ERR4 | \ - BCM43xx_DMAIRQ_ERR5) -#define BCM43xx_DMAIRQ_NONFATALERR BCM43xx_DMAIRQ_ERR3 /* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ #define BCM43xx_DMA_TX_CONTROL 0x00 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c index 22587e0e1a0..865ed5c3361 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -312,20 +312,22 @@ const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { /**** Helper functions to access the device Internal Lookup Tables ****/ -void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); } else { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); } } -u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) { - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); } else { @@ -333,35 +335,3 @@ u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); } } - -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) -{ - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (u16)(val >> 16)); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, (u16)(val & 0x0000FFFF)); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (u16)(val >> 16)); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, (u16)(val & 0x0000FFFF)); - } -} - -u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset) -{ - u32 ret; - - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA2); - ret <<= 16; - ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA2); - ret <<= 16; - ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); - } - - return ret; -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h index d92527fd83e..464521abf73 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h @@ -26,9 +26,7 @@ extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; -void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); -u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset); -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); -u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); #endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index f3cef345c8f..a563258cad3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -155,6 +155,7 @@ static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) val = swab32(val); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); } @@ -225,9 +226,12 @@ void bcm43xx_shm_write32(struct bcm43xx_private *bcm, if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); + mmiowb(); bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value & 0xffff); return; @@ -235,6 +239,7 @@ void bcm43xx_shm_write32(struct bcm43xx_private *bcm, offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); } @@ -246,6 +251,7 @@ void bcm43xx_shm_write16(struct bcm43xx_private *bcm, if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, value); return; @@ -253,6 +259,7 @@ void bcm43xx_shm_write16(struct bcm43xx_private *bcm, offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); } @@ -311,6 +318,7 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status |= BCM43xx_SBF_TIME_UPDATE; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); /* Be careful with the in-progress timer. * First zero out the low register, so we have a full @@ -320,9 +328,10 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) u32 lo = (tsf & 0x00000000FFFFFFFFULL); u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; - barrier(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); } else { u16 v0 = (tsf & 0x000000000000FFFFULL); @@ -330,11 +339,14 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; - barrier(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); } @@ -974,6 +986,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -984,6 +997,13 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; +/* FIXME: It seems like a dummy_transmission corrupts the DMA engines, + * once they are initialized. So avoid doing a dummy_transmission, + * if the DMA engines are running. + */ +if (bcm->initialized) +return; + switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; @@ -1015,24 +1035,28 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x0500, 0x0000); bcm43xx_write16(bcm, 0x0502, 0x0030); + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0017); for (i = 0x00; i < max_loop; i++) { value = bcm43xx_read16(bcm, 0x050E); - if ((value & 0x0080) != 0) + if (value & 0x0080) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x050E); - if ((value & 0x0400) != 0) + if (value & 0x0400) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x0690); - if ((value & 0x0100) == 0) + if (!(value & 0x0100)) break; udelay(10); } + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0037); } static void key_write(struct bcm43xx_private *bcm, @@ -1646,22 +1670,6 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm) } } -/* Debug helper for irq bottom-half to print all reason registers. */ -#define bcmirq_print_reasons(description) \ - do { \ - dprintkl(KERN_ERR PFX description "\n" \ - KERN_ERR PFX " Generic Reason: 0x%08x\n" \ - KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \ - KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \ - reason, \ - dma_reason[0], dma_reason[1], \ - dma_reason[2], dma_reason[3], \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \ - } while (0) - /* Interrupt handler bottom-half */ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) { @@ -1690,9 +1698,30 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) * on DMA or PIO queues. * Maybe we get this in other error conditions, too. */ - bcmirq_print_reasons("XMIT ERROR"); + printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) { + printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + bcm43xx_controller_restart(bcm, "DMA error"); + bcm43xx_unlock_mmio(bcm, flags); + return; + } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) { + printkl(KERN_ERR PFX "DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } if (reason & BCM43xx_IRQ_PS) { handle_irq_ps(bcm); @@ -1780,8 +1809,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_unlock_mmio(bcm, flags); } -#undef bcmirq_print_reasons - static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason, u32 mask) { @@ -3875,6 +3902,7 @@ failure: void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) { bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); schedule_work(&bcm->restart_work); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index d3c2fc1df37..dbbef6ccd15 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -126,6 +126,7 @@ u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); } @@ -255,16 +256,16 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) if (phy->rev == 1) offset = 0x4C00; - bcm43xx_ilt_write16(bcm, offset, 0x00FE); - bcm43xx_ilt_write16(bcm, offset + 1, 0x000D); - bcm43xx_ilt_write16(bcm, offset + 2, 0x0013); - bcm43xx_ilt_write16(bcm, offset + 3, 0x0019); + bcm43xx_ilt_write(bcm, offset, 0x00FE); + bcm43xx_ilt_write(bcm, offset + 1, 0x000D); + bcm43xx_ilt_write(bcm, offset + 2, 0x0013); + bcm43xx_ilt_write(bcm, offset + 3, 0x0019); if (phy->rev == 1) { - bcm43xx_ilt_write16(bcm, 0x1800, 0x2710); - bcm43xx_ilt_write16(bcm, 0x1801, 0x9B83); - bcm43xx_ilt_write16(bcm, 0x1802, 0x9B83); - bcm43xx_ilt_write16(bcm, 0x1803, 0x0F8D); + bcm43xx_ilt_write(bcm, 0x1800, 0x2710); + bcm43xx_ilt_write(bcm, 0x1801, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1802, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D); bcm43xx_phy_write(bcm, 0x0455, 0x0004); } @@ -317,10 +318,10 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x048D, 0x0002); } - bcm43xx_ilt_write16(bcm, offset + 0x0800, 0); - bcm43xx_ilt_write16(bcm, offset + 0x0801, 7); - bcm43xx_ilt_write16(bcm, offset + 0x0802, 16); - bcm43xx_ilt_write16(bcm, offset + 0x0803, 28); + bcm43xx_ilt_write(bcm, offset + 0x0800, 0); + bcm43xx_ilt_write(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write(bcm, offset + 0x0803, 28); } static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) @@ -337,11 +338,11 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0427, 0x001A); for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); } else { /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); @@ -357,36 +358,36 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); for (i = 0; i < 64; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + bcm43xx_ilt_write(bcm, 0x4000 + i, i); for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); } if (phy->rev <= 2) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); else for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); if (phy->rev == 2) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); else if ((phy->rev > 2) && (phy->rev <= 7)) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); if (phy->rev == 1) { for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); for (i = 0; i < 4; i++) { - bcm43xx_ilt_write16(bcm, 0x5404 + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x5408 + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x540C + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x5410 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020); } bcm43xx_phy_agcsetup(bcm); @@ -395,24 +396,24 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) (bcm->board_revision == 0x0017)) return; - bcm43xx_ilt_write16(bcm, 0x5001, 0x0002); - bcm43xx_ilt_write16(bcm, 0x5002, 0x0001); + bcm43xx_ilt_write(bcm, 0x5001, 0x0002); + bcm43xx_ilt_write(bcm, 0x5002, 0x0001); } else { for (i = 0; i <= 0x2F; i++) - bcm43xx_ilt_write16(bcm, 0x1000 + i, 0x0820); + bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820); bcm43xx_phy_agcsetup(bcm); bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ bcm43xx_phy_write(bcm, 0x0403, 0x1000); - bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && (bcm->board_type == 0x0416) && (bcm->board_revision == 0x0017)) return; - bcm43xx_ilt_write16(bcm, 0x0401, 0x0002); - bcm43xx_ilt_write16(bcm, 0x0402, 0x0001); + bcm43xx_ilt_write(bcm, 0x0401, 0x0002); + bcm43xx_ilt_write(bcm, 0x0402, 0x0001); } } @@ -456,11 +457,11 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0035, 0x03FF); bcm43xx_phy_write(bcm, 0x0036, 0x0400); - bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); - bcm43xx_ilt_write16(bcm, 0x3C0C, 0x07BF); + bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF); bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); bcm43xx_phy_write(bcm, 0x0024, 0x4680); @@ -472,47 +473,47 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); bcm43xx_phy_write(bcm, 0x008E, 0x58C1); - bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); - bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); - bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); for (i = 0; i < 16; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, (0x8 + i) & 0x000F); + bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F); - bcm43xx_ilt_write16(bcm, 0x3003, 0x1044); - bcm43xx_ilt_write16(bcm, 0x3004, 0x7201); - bcm43xx_ilt_write16(bcm, 0x3006, 0x0040); - bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + bcm43xx_ilt_write(bcm, 0x3003, 0x1044); + bcm43xx_ilt_write(bcm, 0x3004, 0x7201); + bcm43xx_ilt_write(bcm, 0x3006, 0x0040); + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); bcm43xx_phy_init_noisescaletbl(bcm); for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); break; case 3: for (i = 0; i < 64; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + bcm43xx_ilt_write(bcm, 0x4000 + i, i); - bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); @@ -524,35 +525,35 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x001F, 0x1C00); bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); - bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); bcm43xx_phy_init_noisescaletbl(bcm); for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); bcm43xx_phy_write(bcm, 0x0003, 0x1808); - bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); - - bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); - - bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); - - bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); + + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); break; default: assert(0); @@ -598,19 +599,19 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0019, 0x0000); bcm43xx_radio_write16(bcm, 0x0017, 0x0020); - tval = bcm43xx_ilt_read16(bcm, 0x3001); + tval = bcm43xx_ilt_read(bcm, 0x3001); if (phy->rev == 1) { - bcm43xx_ilt_write16(bcm, 0x3001, - (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFF87) - | 0x0058); + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87) + | 0x0058); } else { - bcm43xx_ilt_write16(bcm, 0x3001, - (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFFC3) - | 0x002C); + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3) + | 0x002C); } bcm43xx_dummy_transmission(bcm); phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); - bcm43xx_ilt_write16(bcm, 0x3001, tval); + bcm43xx_ilt_write(bcm, 0x3001, tval); bcm43xx_radio_set_txpower_a(bcm, 0x0018); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 3901aa99466..4d3b0e85876 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -97,6 +97,7 @@ void bcm43xx_radio_lock(struct bcm43xx_private *bcm) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status |= BCM43xx_SBF_RADIOREG_LOCK; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); udelay(10); } @@ -108,6 +109,7 @@ void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status &= ~BCM43xx_SBF_RADIOREG_LOCK; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); } u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) @@ -142,6 +144,7 @@ u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) { bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); } @@ -161,10 +164,10 @@ static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, } for (i = 0; i < 4; i++) - bcm43xx_ilt_write16(bcm, offset + i, first); + bcm43xx_ilt_write(bcm, offset + i, first); for (i = start; i < end; i++) - bcm43xx_ilt_write16(bcm, offset + i, second); + bcm43xx_ilt_write(bcm, offset + i, second); if (third != -1) { tmp = ((u16)third << 14) | ((u16)third << 6); @@ -196,11 +199,11 @@ static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) tmp |= (i & 0x0001) << 1; tmp |= (i & 0x0002) >> 1; - bcm43xx_ilt_write16(bcm, offset + i, tmp); + bcm43xx_ilt_write(bcm, offset + i, tmp); } for (i = start; i < end; i++) - bcm43xx_ilt_write16(bcm, offset + i, i - start); + bcm43xx_ilt_write(bcm, offset + i, i - start); bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); @@ -316,6 +319,7 @@ u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) { bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); } @@ -612,10 +616,6 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) } break; case BCM43xx_PHYTYPE_G: -//FIXME: Something is broken here. This is called when enabling WLAN interfmode. -// If this is done at runtime, I get an XMIT ERROR and transmission is -// broken. I guess some important register is overwritten by accident. -// The XMIT ERROR comes from the dummy_transmissions in set_gains. if (radio->revision >= 9) return; if (radio->revision == 8) @@ -1641,14 +1641,14 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) base &= 0x000F; bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); - ilt = bcm43xx_ilt_read16(bcm, 0x3001); + ilt = bcm43xx_ilt_read(bcm, 0x3001); ilt &= 0x0007; dac = bcm43xx_get_txgain_dac(txpower); dac <<= 3; dac |= ilt; - bcm43xx_ilt_write16(bcm, 0x3001, dac); + bcm43xx_ilt_write(bcm, 0x3001, dac); bcm->current_core->radio->txpower[0] = txpower; -- cgit v1.2.3-70-g09d2 From e1b1b581b847a5ae9409a02a586476eaba2b3f89 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 15:20:05 +0100 Subject: [PATCH] bcm43xx: receive TX status on MMIO or DMA unconditionally regarding the 80211 core rev. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a563258cad3..3ab02f4f8ec 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1765,22 +1765,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { - if (likely(bcm->current_core->rev < 5)) { - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue3); - else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); - activity = 1; - } else - assert(0); + if (bcm43xx_using_pio(bcm)) + bcm43xx_pio_rx(bcm->current_core->pio->queue3); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + activity = 1; } bcmirq_handled(BCM43xx_IRQ_RX); if (reason & BCM43xx_IRQ_XMIT_STATUS) { - if (bcm->current_core->rev >= 5) { - handle_irq_transmit_status(bcm); - activity = 1; - } + handle_irq_transmit_status(bcm); + activity = 1; //TODO: In AP mode, this also causes sending of powersave responses. bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } -- cgit v1.2.3-70-g09d2 From aae3778176ec7a57b1c4f539b7252acfd7d99a1b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 15:54:56 +0100 Subject: [PATCH] bcm43xx: add functions bcm43xx_dma_read/write, bcm43xx_dma_tx_suspend/resume. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 61 ++++++++++++++++-------------- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 18 +++++++++ 2 files changed, 51 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 0cd29284795..fbe19b922aa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -374,13 +374,11 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) if (ring->tx) { /* Set Transmit Control register to "transmit enable" */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_CONTROL, - BCM43xx_DMA_TXCTRL_ENABLE); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + BCM43xx_DMA_TXCTRL_ENABLE); /* Set Transmit Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, - ring->dmabase + ring->memoffset); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, + ring->dmabase + ring->memoffset); } else { err = alloc_initial_descbuffers(ring); if (err) @@ -388,17 +386,12 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) /* Set Receive Control "receive enable" and frame offset */ value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); value |= BCM43xx_DMA_RXCTRL_ENABLE; - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_CONTROL, - value); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value); /* Set Receive Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, - ring->dmabase + ring->memoffset); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, + ring->dmabase + ring->memoffset); /* Init the descriptor pointer. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, - 200); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200); } out: @@ -411,15 +404,11 @@ static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) if (ring->tx) { bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); /* Zero out Transmit Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, - 0x00000000); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0); } else { bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); /* Zero out Receive Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, - 0x00000000); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0); } } @@ -698,9 +687,8 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, */ wmb(); slot = next_slot(ring, slot); - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_INDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); } static int dma_tx_fragment(struct bcm43xx_dmaring *ring, @@ -940,7 +928,7 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) #endif assert(!ring->tx); - status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); + status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS); descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); current_slot = descptr / sizeof(struct bcm43xx_dmadesc); assert(current_slot >= 0 && current_slot < ring->nr_slots); @@ -953,10 +941,27 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ring->max_used_slots = used_slots; #endif } - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); ring->current_slot = slot; } +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + | BCM43xx_DMA_TXCTRL_SUSPEND); +} + +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + & ~BCM43xx_DMA_TXCTRL_SUSPEND); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); +} + /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index c07e34689be..2d520e4b027 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -140,6 +140,21 @@ struct bcm43xx_dmaring { }; +static inline +u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, + u16 offset) +{ + return bcm43xx_read32(ring->bcm, ring->mmio_base + offset); +} + +static inline +void bcm43xx_dma_write(struct bcm43xx_dmaring *ring, + u16 offset, u32 value) +{ + bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value); +} + + int bcm43xx_dma_init(struct bcm43xx_private *bcm); void bcm43xx_dma_free(struct bcm43xx_private *bcm); @@ -148,6 +163,9 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 dmacontroller_mmio_base); +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); + void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status); -- cgit v1.2.3-70-g09d2 From e9357c056c5e62516f0044e60591d41f00ca7cfa Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 19:27:34 +0100 Subject: [PATCH] bcm43xx: reduce the size of bcm43xx_private by removing unneeded members. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 94 ++++++---- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 7 +- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 238 ++++++++++++------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 128 ++++++------- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 8 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 72 ++++---- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 35 ++-- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 14 +- 13 files changed, 320 insertions(+), 301 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 29c95b07122..a358646ad3e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -556,33 +556,37 @@ struct bcm43xx_pio { #define BCM43xx_MAX_80211_CORES 2 -#define BCM43xx_COREFLAG_AVAILABLE (1 << 0) -#define BCM43xx_COREFLAG_ENABLED (1 << 1) -#define BCM43xx_COREFLAG_INITIALIZED (1 << 2) - #ifdef CONFIG_BCM947XX #define core_offset(bcm) (bcm)->current_core_offset #else #define core_offset(bcm) 0 #endif +/* Generic information about a core. */ struct bcm43xx_coreinfo { - /** Driver internal flags. See BCM43xx_COREFLAG_* */ - u32 flags; + u8 available:1, + enabled:1, + initialized:1; /** core_id ID number */ u16 id; /** core_rev revision number */ u8 rev; /** Index number for _switch_core() */ u8 index; - /* Pointer to the PHYinfo, which belongs to this core (if 80211 core) */ - struct bcm43xx_phyinfo *phy; - /* Pointer to the RadioInfo, which belongs to this core (if 80211 core) */ - struct bcm43xx_radioinfo *radio; - /* Pointer to the DMA rings, which belong to this core (if 80211 core) */ - struct bcm43xx_dma *dma; - /* Pointer to the PIO queues, which belong to this core (if 80211 core) */ - struct bcm43xx_pio *pio; +}; + +/* Additional information for each 80211 core. */ +struct bcm43xx_coreinfo_80211 { + /* PHY device. */ + struct bcm43xx_phyinfo phy; + /* Radio device. */ + struct bcm43xx_radioinfo radio; + union { + /* DMA context. */ + struct bcm43xx_dma dma; + /* PIO context. */ + struct bcm43xx_pio pio; + }; }; /* Context information for a noise calculation (Link Quality). */ @@ -652,7 +656,7 @@ struct bcm43xx_private { #define BCM43xx_NR_LEDS 4 struct bcm43xx_led leds[BCM43xx_NR_LEDS]; - /* The currently active core. NULL if not initialized, yet. */ + /* The currently active core. */ struct bcm43xx_coreinfo *current_core; #ifdef CONFIG_BCM947XX /** current core memory offset */ @@ -665,18 +669,15 @@ struct bcm43xx_private { */ struct bcm43xx_coreinfo core_chipcommon; struct bcm43xx_coreinfo core_pci; - struct bcm43xx_coreinfo core_v90; - struct bcm43xx_coreinfo core_pcmcia; - struct bcm43xx_coreinfo core_ethernet; struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; - /* Info about the PHY for each 80211 core. */ - struct bcm43xx_phyinfo phy[ BCM43xx_MAX_80211_CORES ]; - /* Info about the Radio for each 80211 core. */ - struct bcm43xx_radioinfo radio[ BCM43xx_MAX_80211_CORES ]; - /* DMA */ - struct bcm43xx_dma dma[ BCM43xx_MAX_80211_CORES ]; - /* PIO */ - struct bcm43xx_pio pio[ BCM43xx_MAX_80211_CORES ]; + /* Additional information, specific to the 80211 cores. */ + struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; + /* Index of the current 80211 core. If current_core is not + * an 80211 core, this is -1. + */ + int current_80211_core_idx; + /* Number of available 80211 cores. */ + int nr_80211_available; u32 chipcommon_capabilities; @@ -769,18 +770,39 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm) # error "Using neither DMA nor PIO? Confused..." #endif - +/* Helper functions to access data structures private to the 80211 cores. + * Note that we _must_ have an 80211 core mapped when calling + * any of these functions. + */ static inline -int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) +struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) { - int i, cnt = 0; - - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - if (bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE) - cnt++; - } - - return cnt; + assert(bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); +} +static inline +struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) +{ + assert(!bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); +} +static inline +struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); +} +static inline +struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); } /* Are we running in init_board() context? */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index bcfcebe2826..f73d36b8e0f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -104,16 +104,13 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, fappend("\nCores:\n"); #define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ "rev: 0x%02x, index: 0x%02x\n", \ - (info).flags & BCM43xx_COREFLAG_AVAILABLE \ + (info).available \ ? "available" : "nonavailable", \ - (info).flags & BCM43xx_COREFLAG_ENABLED \ + (info).enabled \ ? "enabled" : "disabled", \ (info).id, (info).rev, (info).index) fappend_core("CHIPCOMMON", bcm->core_chipcommon); fappend_core("PCI", bcm->core_pci); - fappend_core("V90", bcm->core_v90); - fappend_core("PCMCIA", bcm->core_pcmcia); - fappend_core("ETHERNET", bcm->core_ethernet); fappend_core("first 80211", bcm->core_80211[0]); fappend_core("second 80211", bcm->core_80211[1]); #undef fappend_core diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index fbe19b922aa..7ed368a587f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -531,7 +531,7 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); bcm43xx_destroy_dmaring(dma->rx_ring1); dma->rx_ring1 = NULL; @@ -549,7 +549,7 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm) int bcm43xx_dma_init(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; int err = -ENOMEM; @@ -652,7 +652,7 @@ static struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, int *slot) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring = NULL; switch (cookie & 0xF000) { @@ -755,7 +755,7 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, * the device to send the stuff. * Note that this is called from atomic context. */ - struct bcm43xx_dmaring *ring = bcm->current_core->dma->tx_ring1; + struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1; u8 i; struct sk_buff *skb; @@ -784,6 +784,7 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status) { + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c index 865ed5c3361..ad8e569d1fa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -314,7 +314,7 @@ const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); @@ -327,7 +327,7 @@ void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); } else { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 949555da5aa..72a243aac6c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -171,8 +171,8 @@ void bcm43xx_leds_exit(struct bcm43xx_private *bcm) void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) { struct bcm43xx_led *led; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; int i, turn_on; unsigned long interval = 0; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 3ab02f4f8ec..88e9a125c2d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -406,7 +406,7 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ - if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) + if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) return; bcm43xx_write16(bcm, 0x684, 510 + slot_time); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); @@ -443,7 +443,7 @@ static void bcm43xx_disassociate(struct bcm43xx_private *bcm) bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) bcm43xx_short_slot_timing_enable(bcm); @@ -510,8 +510,8 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u32 radio_id; u16 manufact; u16 version; @@ -566,10 +566,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->txpower[2] = 3; else radio->txpower[2] = 0; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else - bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; + radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) @@ -929,15 +929,14 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) struct ieee80211_geo geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; - int i, num80211; + int i; u8 channel; struct bcm43xx_phyinfo *phy; const char *iso_country; memset(&geo, 0, sizeof(geo)); - num80211 = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < num80211; i++) { - phy = bcm->phy + i; + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: @@ -985,8 +984,8 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) */ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -1213,14 +1212,20 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne if (unlikely(!new_core)) return 0; - if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) + if (!new_core->available) return -ENODEV; if (bcm->current_core == new_core) return 0; err = _switch_core(bcm, new_core->index); - if (likely(!err)) - bcm->current_core = new_core; + if (unlikely(err)) + goto out; + bcm->current_core = new_core; + bcm->current_80211_core_idx = -1; + if (new_core->id == BCM43xx_COREID_80211) + bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); + +out: return err; } @@ -1295,7 +1300,8 @@ static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); out: - bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED; + bcm->current_core->enabled = 0; + return 0; } @@ -1340,7 +1346,7 @@ static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); - bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED; + bcm->current_core->enabled = 1; assert(err == 0); out: return err; @@ -1411,7 +1417,7 @@ static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { old_core = bcm->current_core; err = bcm43xx_switch_core(bcm, active_80211_core); if (err) @@ -1433,9 +1439,6 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm) u16 tmp; struct bcm43xx_xmitstatus stat; - assert(bcm->current_core->id == BCM43xx_COREID_80211); - assert(bcm->current_core->rev >= 5); - while (1) { v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); if (!v0) @@ -1473,7 +1476,7 @@ static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); assert(bcm->noisecalc.core_at_start == bcm->current_core); - assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel); + assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel); } static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) @@ -1483,7 +1486,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) if (bcm->noisecalc.calculation_running) return; bcm->noisecalc.core_at_start = bcm->current_core; - bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel; + bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; bcm->noisecalc.calculation_running = 1; bcm->noisecalc.nr_samples = 0; @@ -1492,7 +1495,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) static void handle_irq_noise(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; u8 noise[4]; u8 i, j; @@ -1759,16 +1762,16 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue0); + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue3); + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1); activity = 1; } bcmirq_handled(BCM43xx_IRQ_RX); @@ -1911,7 +1914,7 @@ static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u8 rev = bcm->current_core->rev; int err = 0; int nr; @@ -2349,6 +2352,8 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) */ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; int iw_mode = bcm->ieee->iw_mode; int tmp; @@ -2388,13 +2393,13 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_radio_off; /* Select initial Interference Mitigation. */ - tmp = bcm->current_core->radio->interfmode; - bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + tmp = radio->interfmode; + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; bcm43xx_radio_set_interference_mitigation(bcm, tmp); bcm43xx_phy_set_antenna_diversity(bcm); bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + if (phy->type == BCM43xx_PHYTYPE_B) { value16 = bcm43xx_read16(bcm, 0x005E); value16 |= 0x0004; bcm43xx_write16(bcm, 0x005E, value16); @@ -2512,6 +2517,32 @@ error: return -ENODEV; } +void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) +{ + /* Initialize a "phyinfo" structure. The structure is already + * zeroed out. + */ + phy->antenna_diversity = 0xFFFF; + phy->savedpctlreg = 0xFFFF; + phy->minlowsig[0] = 0xFFFF; + phy->minlowsig[1] = 0xFFFF; + spin_lock_init(&phy->lock); +} + +void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) +{ + /* Initialize a "radioinfo" structure. The structure is already + * zeroed out. + */ + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + radio->channel = 0xFF; + radio->initial_channel = 0xFF; + radio->lofcal = 0xFFFF; + radio->initval = 0xFFFF; + radio->nrssi[0] = -1000; + radio->nrssi[1] = -1000; +} + static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) { int err, i; @@ -2523,15 +2554,14 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo)); memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) * BCM43xx_MAX_80211_CORES); - - memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo) - * BCM43xx_MAX_80211_CORES); - memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo) - * BCM43xx_MAX_80211_CORES); + memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) + * BCM43xx_MAX_80211_CORES); + bcm->current_80211_core_idx = -1; + bcm->nr_80211_available = 0; + bcm->current_core = NULL; + bcm->active_80211_core = NULL; /* map core 0 */ err = _switch_core(bcm, 0); @@ -2549,7 +2579,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) if (core_id == BCM43xx_COREID_CHIPCOMMON) { chip_id_32 = bcm43xx_read32(bcm, 0); chip_id_16 = chip_id_32 & 0xFFFF; - bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE; + bcm->core_chipcommon.available = 1; bcm->core_chipcommon.id = core_id; bcm->core_chipcommon.rev = core_rev; bcm->core_chipcommon.index = 0; @@ -2618,18 +2648,19 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", bcm->chip_id, bcm->chip_rev); dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); - if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) { + if (bcm->core_chipcommon.available) { dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", core_id, core_rev, core_vendor, bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); } - if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) + if (bcm->core_chipcommon.available) current_core = 1; else current_core = 0; for ( ; current_core < core_count; current_core++) { struct bcm43xx_coreinfo *core; + struct bcm43xx_coreinfo_80211 *ext_80211; err = _switch_core(bcm, current_core); if (err) @@ -2651,36 +2682,16 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) switch (core_id) { case BCM43xx_COREID_PCI: core = &bcm->core_pci; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + if (core->available) { printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); continue; } break; - case BCM43xx_COREID_V90: - core = &bcm->core_v90; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple V90 cores found.\n"); - continue; - } - break; - case BCM43xx_COREID_PCMCIA: - core = &bcm->core_pcmcia; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n"); - continue; - } - break; - case BCM43xx_COREID_ETHERNET: - core = &bcm->core_ethernet; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n"); - continue; - } - break; case BCM43xx_COREID_80211: for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { core = &(bcm->core_80211[i]); - if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE)) + ext_80211 = &(bcm->core_80211_ext[i]); + if (!core->available) break; core = NULL; } @@ -2715,40 +2726,23 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) err = -ENODEV; goto out; } - core->phy = &bcm->phy[i]; - core->phy->antenna_diversity = 0xffff; - core->phy->savedpctlreg = 0xFFFF; - core->phy->minlowsig[0] = 0xFFFF; - core->phy->minlowsig[1] = 0xFFFF; - core->phy->minlowsigpos[0] = 0; - core->phy->minlowsigpos[1] = 0; - spin_lock_init(&core->phy->lock); - core->radio = &bcm->radio[i]; - core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; - core->radio->channel = 0xFF; - core->radio->initial_channel = 0xFF; - core->radio->lofcal = 0xFFFF; - core->radio->initval = 0xFFFF; - core->radio->nrssi[0] = -1000; - core->radio->nrssi[1] = -1000; - core->dma = &bcm->dma[i]; - core->pio = &bcm->pio[i]; + bcm->nr_80211_available++; + bcm43xx_init_struct_phyinfo(&ext_80211->phy); + bcm43xx_init_struct_radioinfo(&ext_80211->radio); break; case BCM43xx_COREID_CHIPCOMMON: printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); break; - default: - printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id); } if (core) { - core->flags |= BCM43xx_COREFLAG_AVAILABLE; + core->available = 1; core->id = core_id; core->rev = core_rev; core->index = current_core; } } - if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) { + if (!bcm->core_80211[0].available) { printk(KERN_ERR PFX "Error: No 80211 core found!\n"); err = -ENODEV; goto out; @@ -2802,7 +2796,7 @@ static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) { - switch (bcm->current_core->phy->type) { + switch (bcm43xx_current_phy(bcm)->type) { case BCM43xx_PHYTYPE_A: case BCM43xx_PHYTYPE_G: bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); @@ -2829,12 +2823,14 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) bcm43xx_pio_free(bcm); bcm43xx_dma_free(bcm); - bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED; + bcm->current_core->initialized = 0; } /* http://bcm-specs.sipsolutions.net/80211Init */ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u32 ucodeflags; int err; u32 sbimconfiglow; @@ -2867,16 +2863,15 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) /* HW decryption needs to be set now */ ucodeflags |= 0x40000000; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_G) { ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if (bcm->current_core->phy->rev == 1) + if (phy->rev == 1) ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; - } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + } else if (phy->type == BCM43xx_PHYTYPE_B) { ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if ((bcm->current_core->phy->rev >= 2) && - (bcm->current_core->radio->version == 0x2050)) + if (phy->rev >= 2 && radio->version == 0x2050) ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; } @@ -2901,7 +2896,7 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) bcm43xx_rate_memory_init(bcm); /* Minimum Contention Window */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) + if (phy->type == BCM43xx_PHYTYPE_B) bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); else bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); @@ -2927,7 +2922,7 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) bcm43xx_mac_enable(bcm); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED; + bcm->current_core->initialized = 1; out: return err; @@ -3048,7 +3043,7 @@ static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) return; @@ -3076,8 +3071,8 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (phy->type == BCM43xx_PHYTYPE_G) { //TODO: update_aci_moving_average @@ -3170,9 +3165,9 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_unlock(bcm, flags); for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) + if (!bcm->core_80211[i].available) continue; - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + if (!bcm->core_80211[i].initialized) continue; err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); @@ -3190,7 +3185,6 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) static int bcm43xx_init_board(struct bcm43xx_private *bcm) { int i, err; - int num_80211_cores; int connect_phy; unsigned long flags; @@ -3212,8 +3206,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) goto err_crystal_off; tasklet_enable(&bcm->isr_tasklet); - num_80211_cores = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < num_80211_cores; i++) { + for (i = 0; i < bcm->nr_80211_available; i++) { err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); assert(err != -ENODEV); if (err) @@ -3223,8 +3216,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) * Connect PHY only on the first core. */ if (!bcm43xx_core_enabled(bcm)) { - if (num_80211_cores == 1) { - connect_phy = bcm->current_core->phy->connected; + if (bcm->nr_80211_available == 1) { + connect_phy = bcm43xx_current_phy(bcm)->connected; } else { if (i == 0) connect_phy = 1; @@ -3248,7 +3241,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) } } bcm->active_80211_core = &bcm->core_80211[0]; - if (num_80211_cores >= 2) { + if (bcm->nr_80211_available >= 2) { bcm43xx_switch_core(bcm, &bcm->core_80211[0]); bcm43xx_mac_enable(bcm); } @@ -3260,9 +3253,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); - if (bcm->current_core->radio->initial_channel != 0xFF) { + if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); + bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); bcm43xx_mac_enable(bcm); } @@ -3282,8 +3275,8 @@ out: err_80211_unwind: tasklet_disable(&bcm->isr_tasklet); /* unwind all 80211 initialization */ - for (i = 0; i < num_80211_cores; i++) { - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + for (i = 0; i < bcm->nr_80211_available; i++) { + if (!bcm->core_80211[i].initialized) continue; bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_wireless_core_cleanup(bcm); @@ -3307,15 +3300,15 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm) /* Free allocated structures/fields */ for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->phy[i]._lo_pairs); - if (bcm->phy[i].dyn_tssi_tbl) - kfree(bcm->phy[i].tssi2dbm); + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); } } static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 value; u8 phy_version; u8 phy_type; @@ -3393,7 +3386,6 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) int i; void __iomem *ioaddr; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - int num_80211_cores; u32 coremask; err = pci_enable_device(pci_dev); @@ -3467,11 +3459,9 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) if (err) goto err_chipset_detach; - num_80211_cores = bcm43xx_num_80211_cores(bcm); - /* Attach all IO cores to the backplane. */ coremask = 0; - for (i = 0; i < num_80211_cores; i++) + for (i = 0; i < bcm->nr_80211_available; i++) coremask |= (1 << bcm->core_80211[i].index); //FIXME: Also attach some non80211 cores? err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); @@ -3487,7 +3477,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) if (err) goto err_chipset_detach; - for (i = 0; i < num_80211_cores; i++) { + for (i = 0; i < bcm->nr_80211_available; i++) { err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); assert(err != -ENODEV); if (err) @@ -3519,7 +3509,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); @@ -3535,9 +3525,9 @@ out: err_80211_unwind: for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->phy[i]._lo_pairs); - if (bcm->phy[i].dyn_tssi_tbl) - kfree(bcm->phy[i].tssi2dbm); + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); } err_chipset_detach: bcm43xx_chipset_detach(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 086136c3d01..eca79a38594 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -80,7 +80,7 @@ static inline u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, int freq) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_freq_to_channel_a(freq); return bcm43xx_freq_to_channel_bg(freq); } @@ -107,7 +107,7 @@ static inline int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_channel_to_freq_a(channel); return bcm43xx_channel_to_freq_bg(channel); } @@ -129,7 +129,7 @@ static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_is_valid_channel_a(channel); return bcm43xx_is_valid_channel_bg(channel); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index dbbef6ccd15..1ce9a459990 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -83,7 +83,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); assert(irqs_disabled()); if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { @@ -102,7 +102,7 @@ void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); assert(irqs_disabled()); if (bcm->current_core->rev < 3) { @@ -132,7 +132,7 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); unsigned long flags; bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ @@ -158,39 +158,32 @@ void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) */ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u32 flags; - if (bcm->current_core->rev < 5) { - if (connect) { - bcm->current_core->phy->connected = 1; - dprintk(KERN_INFO PFX "PHY connected\n"); - } else { - bcm->current_core->phy->connected = 0; - dprintk(KERN_INFO PFX "PHY disconnected\n"); - } - return 0; - } - + if (bcm->current_core->rev < 5) + goto out; + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (connect) { if (!(flags & 0x00010000)) return -ENODEV; - bcm->current_core->phy->connected = 1; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); flags |= (0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - dprintk(KERN_INFO PFX "PHY connected\n"); } else { if (!(flags & 0x00020000)) return -ENODEV; - bcm->current_core->phy->connected = 0; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); flags &= ~(0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - dprintk(KERN_INFO PFX "PHY disconnected\n"); } +out: + phy->connected = connect; + if (connect) + dprintk(KERN_INFO PFX "PHY connected\n"); + else + dprintk(KERN_INFO PFX "PHY disconnected\n"); return 0; } @@ -200,8 +193,8 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) */ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; int must_reset_txpower = 0; @@ -250,7 +243,7 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 offset = 0x0000; if (phy->rev == 1) @@ -326,7 +319,7 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; assert(phy->type == BCM43xx_PHYTYPE_G); @@ -420,7 +413,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) /* Initialize the noisescaletable for APHY */ static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int i; bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); @@ -448,10 +441,11 @@ static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; - assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_A); - switch (bcm->current_core->phy->rev) { + assert(phy->type == BCM43xx_PHYTYPE_A); + switch (phy->rev) { case 2: bcm43xx_phy_write(bcm, 0x008E, 0x3800); bcm43xx_phy_write(bcm, 0x0035, 0x03FF); @@ -563,7 +557,8 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) /* Initialize APHY. This is also called for the GPHY in some cases. */ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tval; if (phy->type == BCM43xx_PHYTYPE_A) { @@ -586,11 +581,11 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { - if (bcm->current_core->radio->lofcal == 0xFFFF) { + if (radio->lofcal == 0xFFFF) { TODO();//TODO: LOF Cal bcm43xx_radio_set_tx_iq(bcm); } else - bcm43xx_radio_write16(bcm, 0x001E, bcm->current_core->radio->lofcal); + bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal); } bcm43xx_phy_write(bcm, 0x007A, 0xF111); @@ -620,7 +615,7 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_write16(bcm, 0x03EC, 0x3F22); @@ -671,7 +666,7 @@ static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_write16(bcm, 0x03EC, 0x3F22); @@ -729,8 +724,8 @@ static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset; if (phy->version == 1 && @@ -835,8 +830,8 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_phy_write(bcm, 0x003E, 0x817A); @@ -946,9 +941,9 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) udelay(40); bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - if ((bcm->current_core->radio->manufact == 0x17F) && - (bcm->current_core->radio->version == 0x2050) && - (bcm->current_core->radio->revision <= 2)) { + if (radio->manufact == 0x17F && + radio->version == 0x2050 && + radio->revision <= 2) { bcm43xx_radio_write16(bcm, 0x0050, 0x0020); bcm43xx_radio_write16(bcm, 0x005A, 0x0070); bcm43xx_radio_write16(bcm, 0x005B, 0x007B); @@ -1001,8 +996,8 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; if (phy->rev == 1) @@ -1096,8 +1091,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 regstack[12] = { 0 }; u16 mls; u16 fval; @@ -1190,7 +1185,9 @@ void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) static inline u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) { - if (bcm->current_core->phy->connected) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (phy->connected) { bcm43xx_phy_write(bcm, 0x15, 0xE300); control <<= 8; bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); @@ -1242,7 +1239,7 @@ void bcm43xx_lo_write(struct bcm43xx_private *bcm, "WARNING: Writing invalid LOpair " "(low: %d, high: %d, index: %lu)\n", pair->low, pair->high, - (unsigned long)(pair - bcm->current_core->phy->_lo_pairs)); + (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs)); dump_stack(); } #endif @@ -1257,7 +1254,7 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, u16 tx) { static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation > 6) baseband_attenuation = 6; @@ -1275,10 +1272,12 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, static inline struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + return bcm43xx_find_lopair(bcm, - bcm->current_core->radio->txpower[0], - bcm->current_core->radio->txpower[1], - bcm->current_core->radio->txpower[2]); + radio->txpower[0], + radio->txpower[1], + radio->txpower[2]); } /* Adjust B/G LO */ @@ -1294,9 +1293,9 @@ void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) bcm43xx_lo_write(bcm, pair); } -static inline -void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) +static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 txctl2 = 0, i; u32 smallest, tmp; @@ -1312,7 +1311,7 @@ void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) txctl2 = i; } } - bcm->current_core->radio->txpower[3] = txctl2; + radio->txpower[3] = txctl2; } static @@ -1402,16 +1401,17 @@ void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, u16 baseband_attenuation) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 value; - if (bcm->current_core->phy->version == 0) { + if (phy->version == 0) { value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); value |= (baseband_attenuation & 0x000F); bcm43xx_write16(bcm, 0x03E6, value); return; } - if (bcm->current_core->phy->version > 1) { + if (phy->version > 1) { value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; value |= (baseband_attenuation << 2) & 0x003C; } else { @@ -1426,8 +1426,8 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) { static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; const int is_initializing = bcm43xx_is_initializing(bcm); - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 h, i, oldi = 0, j; struct bcm43xx_lopair control; struct bcm43xx_lopair *tmp_control; @@ -1653,7 +1653,7 @@ void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_lopair *pair; int i; @@ -1668,7 +1668,7 @@ void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) */ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s8 dbm = 0; s32 tmp; @@ -1698,8 +1698,8 @@ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (phy->savedpctlreg == 0xFFFF) return; @@ -1880,8 +1880,8 @@ s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 pab0, pab1, pab2; u8 idx; s8 *dyn_tssi2dbm; @@ -1958,7 +1958,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) int bcm43xx_phy_init(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err = -ENODEV; unsigned long flags; @@ -2008,7 +2008,7 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 antennadiv; u16 offset; u16 value; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 26dc6047d45..7bddae910de 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -146,7 +146,7 @@ struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, struct bcm43xx_pio_txpacket **packet) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); struct bcm43xx_pioqueue *queue = NULL; int packetindex; @@ -377,7 +377,7 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); bcm43xx_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; @@ -391,7 +391,7 @@ void bcm43xx_pio_free(struct bcm43xx_private *bcm) int bcm43xx_pio_init(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); struct bcm43xx_pioqueue *queue; int err = -ENOMEM; @@ -438,7 +438,7 @@ err_destroy0: int bcm43xx_pio_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb) { - struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1; + struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; struct bcm43xx_pio_txpacket *packet; u16 tmp; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 4d3b0e85876..07a6169a0b3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -114,8 +114,8 @@ void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); switch (phy->type) { case BCM43xx_PHYTYPE_A: @@ -151,7 +151,7 @@ void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, s16 first, s16 second, s16 third) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; u16 start = 0x08, end = 0x18; u16 offset = 0x0400; @@ -183,7 +183,7 @@ static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i, tmp; u16 offset = 0x0400; u16 start = 0x0008, end = 0x0018; @@ -217,7 +217,7 @@ static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) /* Synthetic PU workaround */ static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (radio->version != 0x2050 || radio->revision >= 6) { /* We do not need the workaround. */ @@ -238,7 +238,7 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u8 ret = 0; u16 saved, rssi, temp; int i, j = 0; @@ -269,8 +269,8 @@ u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u8 ret[13]; unsigned int channel = radio->channel; unsigned int i, j, start, end; @@ -351,22 +351,23 @@ void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 i, delta; s32 tmp; - delta = 0x1F - bcm->current_core->radio->nrssi[0]; + delta = 0x1F - radio->nrssi[0]; for (i = 0; i < 64; i++) { - tmp = (i - delta) * bcm->current_core->radio->nrssislope; + tmp = (i - delta) * radio->nrssislope; tmp /= 0x10000; tmp += 0x3A; tmp = limit_value(tmp, 0, 0x3F); - bcm->current_core->radio->nrssi_lt[i] = tmp; + radio->nrssi_lt[i] = tmp; } } static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 backup[20] = { 0 }; s16 v47F; u16 i; @@ -531,8 +532,8 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 backup[18] = { 0 }; u16 tmp; s16 nrssi0, nrssi1; @@ -779,8 +780,8 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 threshold; s32 a, b; int tmp; @@ -804,7 +805,7 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) radiotype = 1; if (radiotype == 1) { - threshold = bcm->current_core->radio->nrssi[1] - 5; + threshold = radio->nrssi[1] - 5; } else { threshold = 40 * radio->nrssi[0]; threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); @@ -901,8 +902,8 @@ static void bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int i = 0; u16 *stack = radio->interfstack; u16 tmp, flipped; @@ -1052,8 +1053,8 @@ static void bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int i = 0; u16 *stack = radio->interfstack; u16 tmp, flipped; @@ -1142,8 +1143,8 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int currentmode; if ((phy->type != BCM43xx_PHYTYPE_G) || @@ -1199,8 +1200,8 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 backup[19] = { 0 }; u16 ret; u16 i, j; @@ -1444,7 +1445,7 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, int synthetic_pu_workaround) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 r8, tmp; u16 freq; @@ -1628,6 +1629,7 @@ static u16 bcm43xx_get_txgain_dac(u16 txpower) void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 pamp, base, dac, ilt; txpower = limit_value(txpower, 0, 63); @@ -1650,7 +1652,7 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) bcm43xx_ilt_write(bcm, 0x3001, dac); - bcm->current_core->radio->txpower[0] = txpower; + radio->txpower[0] = txpower; TODO(); //TODO: FuncPlaceholder (Adjust BB loft cancel) @@ -1660,8 +1662,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, u16 baseband_attenuation, u16 radio_attenuation, u16 txpower) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation == 0xFFFF) baseband_attenuation = radio->txpower[0]; @@ -1698,8 +1700,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int err; if (radio->enabled) @@ -1730,8 +1732,8 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); @@ -1750,7 +1752,9 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) { - switch (bcm->current_core->phy->type) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + switch (phy->type) { case BCM43xx_PHYTYPE_A: bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 713ec601c34..35c3c9704c3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -150,7 +150,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, bcm43xx_lock(bcm, flags); assert(bcm->initialized); - switch (bcm->current_core->radio->interfmode) { + switch (bcm43xx_current_radio(bcm)->interfmode) { case BCM43xx_RADIO_INTERFMODE_NONE: count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); break; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 208193851e8..651ba605495 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -56,15 +56,14 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - int i, nr_80211; + int i; struct bcm43xx_phyinfo *phy; char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; bcm43xx_lock(bcm, flags); - nr_80211 = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < nr_80211; i++) { - phy = bcm->phy + i; + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { case BCM43xx_PHYTYPE_A: have_a = 1; @@ -129,7 +128,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, err = bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); } else { - bcm->current_core->radio->initial_channel = channel; + bcm43xx_current_radio(bcm)->initial_channel = channel; err = 0; } out_unlock: @@ -144,15 +143,17 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; int err = -ENODEV; u16 channel; bcm43xx_lock(bcm, flags); - channel = bcm->current_core->radio->channel; + radio = bcm43xx_current_radio(bcm); + channel = radio->channel; if (channel == 0xFF) { assert(!bcm->initialized); - channel = bcm->current_core->radio->initial_channel; + channel = radio->initial_channel; if (channel == 0xFF) goto out_unlock; } @@ -232,6 +233,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, const struct ieee80211_geo *geo; unsigned long flags; int i, j; + struct bcm43xx_phyinfo *phy; data->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -270,11 +272,12 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, IW_ENC_CAPA_CIPHER_CCMP; bcm43xx_lock(bcm, flags); + phy = bcm43xx_current_phy(bcm); range->num_bitrates = 0; i = 0; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A || - bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_A || + phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates = 8; range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; @@ -285,8 +288,8 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; } - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B || - bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates += 4; range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; @@ -461,8 +464,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) goto out_unlock; - radio = bcm->current_core->radio; - phy = bcm->current_core->phy; + radio = bcm43xx_current_radio(bcm); + phy = bcm43xx_current_phy(bcm); if (data->txpower.disabled != (!(radio->enabled))) { if (data->txpower.disabled) bcm43xx_radio_turn_off(bcm); @@ -500,7 +503,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, bcm43xx_lock(bcm, flags); if (!bcm->initialized) goto out_unlock; - radio = bcm->current_core->radio; + radio = bcm43xx_current_radio(bcm); /* desired dBm value is in Q5.2 */ data->txpower.value = radio->txpower_desired >> 2; data->txpower.fixed = 1; @@ -645,7 +648,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, "not supported while the interface is down.\n"); err = -ENODEV; } else - bcm->current_core->radio->interfmode = mode; + bcm43xx_current_radio(bcm)->interfmode = mode; } bcm43xx_unlock_mmio(bcm, flags); @@ -662,7 +665,7 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, int mode; bcm43xx_lock(bcm, flags); - mode = bcm->current_core->radio->interfmode; + mode = bcm43xx_current_radio(bcm)->interfmode; bcm43xx_unlock(bcm, flags); switch (mode) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 5ee572e79f6..c4809da8e9c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -284,7 +284,7 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, const int is_first_fragment, const u16 cookie) { - const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; const struct ieee80211_security *secinfo = &bcm->ieee->sec; u8 bitrate; @@ -382,8 +382,8 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, int ofdm, int adjust_2053, int adjust_2050) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s32 tmp; switch (radio->version) { @@ -442,7 +442,7 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s8 ret; if (phy->type == BCM43xx_PHYTYPE_A) { @@ -458,6 +458,8 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, struct sk_buff *skb, struct bcm43xx_rxhdr *rxhdr) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_plcp_hdr4 *plcp; struct ieee80211_rx_stats stats; struct ieee80211_hdr_4addr *wlhdr; @@ -494,13 +496,13 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, else stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); - stats.received_channel = bcm->current_core->radio->channel; + stats.received_channel = radio->channel; //TODO stats.control = stats.mask = IEEE80211_STATMASK_SIGNAL | //TODO IEEE80211_STATMASK_NOISE | IEEE80211_STATMASK_RATE | IEEE80211_STATMASK_RSSI; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (phy->type == BCM43xx_PHYTYPE_A) stats.freq = IEEE80211_52GHZ_BAND; else stats.freq = IEEE80211_24GHZ_BAND; -- cgit v1.2.3-70-g09d2 From 49f29efa7f44a79b64c7882c68e171898d0495a0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 14 Mar 2006 16:05:26 +0100 Subject: [PATCH] bcm43xx: Fix crash on ifdown, by being careful in pio/dma freeing. This bug was caused by the packing of the bcm43xx_dma and bcm43xx_pio structures into a union. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 6 +++++- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 7ed368a587f..9c64438b767 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -531,7 +531,11 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); + struct bcm43xx_dma *dma; + + if (bcm43xx_using_pio(bcm)) + return; + dma = bcm43xx_current_dma(bcm); bcm43xx_destroy_dmaring(dma->rx_ring1); dma->rx_ring1 = NULL; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 7bddae910de..5b6f0a84d01 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -377,7 +377,11 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); + struct bcm43xx_pio *pio; + + if (!bcm43xx_using_pio(bcm)) + return; + pio = bcm43xx_current_pio(bcm); bcm43xx_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; -- cgit v1.2.3-70-g09d2 From 4cf6f03e067d6d416f5c9219471daf64703afae4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 14 Mar 2006 18:23:43 +0100 Subject: [PATCH] bcm43xx: Remove the workaround in dummy_transmission, as it causes more trouble than it solves Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 88e9a125c2d..cc8efe74f53 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -996,13 +996,6 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; -/* FIXME: It seems like a dummy_transmission corrupts the DMA engines, - * once they are initialized. So avoid doing a dummy_transmission, - * if the DMA engines are running. - */ -if (bcm->initialized) -return; - switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; -- cgit v1.2.3-70-g09d2 From b3db5e553876c1743eefae5963aea431ec4d5ba6 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 15 Mar 2006 16:31:45 +0100 Subject: [PATCH] bcm43xx: Do boardflags workarounds for specific boards. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 4 ++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 +++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index a358646ad3e..8820012b4b3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -120,6 +120,10 @@ #define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ #define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ #define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ +#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */ +#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ /* GPIO register offset, in both ChipCommon and PCI core. */ #define BCM43xx_GPIO_CONTROL 0x6c diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index cc8efe74f53..e26507b11f0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -910,6 +910,15 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) if (value == 0xFFFF) value = 0x0000; bcm->sprom.boardflags = value; + /* boardflags workarounds */ + if (bcm->board_vendor == PCI_VENDOR_ID_DELL && + bcm->chip_id == 0x4301 && + bcm->board_revision == 0x74) + bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST; + if (bcm->board_vendor == PCI_VENDOR_ID_APPLE && + bcm->board_type == 0x4E && + bcm->board_revision > 0x40) + bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL; /* antenna gain */ value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; -- cgit v1.2.3-70-g09d2 From 5808bbbdf8c095745f0cac9110b245102243b243 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 15 Mar 2006 18:13:53 +0100 Subject: [PATCH] bcm43xx: properly mask txctl1 before writing it to hardware. This should not make a difference, but be careful to not trash the register. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 07a6169a0b3..cac604bc095 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1690,8 +1690,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); if (radio->version == 0x2050) { bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F) - | (txpower << 4)); + (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) + | ((txpower << 4) & 0x0070)); } if (phy->type == BCM43xx_PHYTYPE_G) bcm43xx_phy_lo_adjust(bcm, 0); -- cgit v1.2.3-70-g09d2 From 4a1821e4c7a84569f788b7667affe2743317b63f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 18 Mar 2006 20:19:12 +0100 Subject: [PATCH] bcm43xx: remove check for mmio length, as it differs among platforms. (especially embedded) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 30 ++++------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e26507b11f0..6a877df2ecf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3386,23 +3386,17 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) struct net_device *net_dev = bcm->net_dev; int err; int i; - void __iomem *ioaddr; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + unsigned long mmio_start, mmio_flags, mmio_len; u32 coremask; err = pci_enable_device(pci_dev); if (err) { printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); - err = -ENODEV; goto out; } - mmio_start = pci_resource_start(pci_dev, 0); - mmio_end = pci_resource_end(pci_dev, 0); mmio_flags = pci_resource_flags(pci_dev, 0); mmio_len = pci_resource_len(pci_dev, 0); - - /* make sure PCI base addr is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk(KERN_ERR PFX "%s, region #0 not an MMIO resource, aborting\n", @@ -3410,39 +3404,23 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) err = -ENODEV; goto err_pci_disable; } -//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there? -#ifndef CONFIG_BCM947XX - if (mmio_len != BCM43xx_IO_SIZE) { - printk(KERN_ERR PFX - "%s: invalid PCI mem region size(s), aborting\n", - pci_name(pci_dev)); - err = -ENODEV; - goto err_pci_disable; - } -#endif - err = pci_request_regions(pci_dev, KBUILD_MODNAME); if (err) { printk(KERN_ERR PFX "could not access PCI resources (%i)\n", err); goto err_pci_disable; } - /* enable PCI bus-mastering */ pci_set_master(pci_dev); - - /* ioremap MMIO region */ - ioaddr = ioremap(mmio_start, mmio_len); - if (!ioaddr) { + bcm->mmio_addr = ioremap(mmio_start, mmio_len); + if (!bcm->mmio_addr) { printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pci_dev)); err = -EIO; goto err_pci_release; } - - net_dev->base_addr = (unsigned long)ioaddr; - bcm->mmio_addr = ioaddr; bcm->mmio_len = mmio_len; + net_dev->base_addr = (unsigned long)bcm->mmio_addr; bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, &bcm->board_vendor); -- cgit v1.2.3-70-g09d2 From 714eece7c7c300bbc5e8285890e7374958ca37f4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 18 Mar 2006 21:28:46 +0100 Subject: [PATCH] bcm43xx: fix some gpio register trashing (hopefully :D) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 16 +++++-- drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 71 ++++++++++++++--------------- 3 files changed, 46 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 72a243aac6c..c8f5ad75d2a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -165,7 +165,7 @@ void bcm43xx_leds_exit(struct bcm43xx_private *bcm) led = &(bcm->leds[i]); bcm43xx_led_blink_stop(led, 1); } - bcm43xx_leds_turn_off(bcm); + bcm43xx_leds_switch_all(bcm, 0); } void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) @@ -268,18 +268,26 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } -void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm) +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) { struct bcm43xx_led *led; - u16 ledctl = 0; + u16 ledctl; int i; + int bit_on; + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); if (led->behaviour == BCM43xx_LED_INACTIVE) continue; - if (led->activelow) + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) ledctl |= (1 << i); + else + ledctl &= ~(1 << i); } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h index 6f18e2f95db..d3716cf3aeb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -51,6 +51,6 @@ enum { /* LED behaviour values */ int bcm43xx_leds_init(struct bcm43xx_private *bcm); void bcm43xx_leds_exit(struct bcm43xx_private *bcm); void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); -void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm); +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on); #endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6a877df2ecf..eb8fca8279f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2182,13 +2182,10 @@ static int switch_to_gpio_core(struct bcm43xx_private *bcm) if (unlikely(err == -ENODEV)) { printk(KERN_ERR PFX "gpio error: " "Neither ChipCommon nor PCI core available!\n"); - return -ENODEV; - } else if (unlikely(err != 0)) - return -ENODEV; - } else if (unlikely(err != 0)) - return -ENODEV; + } + } - return 0; + return err; } /* Initialize the GPIOs @@ -2198,45 +2195,48 @@ static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) { struct bcm43xx_coreinfo *old_core; int err; - u32 mask, value; + u32 mask, set; - value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value &= ~0xc000; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & 0xFFFF3FFF); - mask = 0x0000001F; - value = 0x0000000F; - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, - bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0); + bcm43xx_leds_switch_all(bcm, 0); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); - old_core = bcm->current_core; - - err = switch_to_gpio_core(bcm); - if (err) - return err; - - if (bcm->current_core->rev >= 2){ - mask |= 0x10; - value |= 0x10; - } + mask = 0x0000001F; + set = 0x0000000F; if (bcm->chip_id == 0x4301) { - mask |= 0x60; - value |= 0x60; + mask |= 0x0060; + set |= 0x0060; + } + if (0 /* FIXME: conditional unknown */) { + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0100); + mask |= 0x0180; + set |= 0x0180; } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { - mask |= 0x200; - value |= 0x200; + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; } + if (bcm->current_core->rev >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + goto out; bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, - (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value); - + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set); err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - - return 0; +out: + return err; } /* Turn off all GPIO stuff. Call this on module unload, for example. */ @@ -2384,11 +2384,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); - if (modparam_noleds) - bcm43xx_leds_turn_off(bcm); - else - bcm43xx_leds_update(bcm, 0); - bcm43xx_write16(bcm, 0x03E6, 0x0000); err = bcm43xx_phy_init(bcm); if (err) -- cgit v1.2.3-70-g09d2 From 6ab5b8e670c4bb7ac0035ec3c6d6a161fae12009 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Mar 2006 17:18:48 +0100 Subject: [PATCH] bcm43xx: merge all iwmode code into the set_iwmode function. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 65 +++++++++++++---------------- 1 file changed, 29 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index eb8fca8279f..a85176325e9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2292,50 +2292,60 @@ void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode) { unsigned long flags; + struct net_device *net_dev = bcm->net_dev; u32 status; + u16 value; spin_lock_irqsave(&bcm->ieee->lock, flags); bcm->ieee->iw_mode = iw_mode; spin_unlock_irqrestore(&bcm->ieee->lock, flags); if (iw_mode == IW_MODE_MONITOR) - bcm->net_dev->type = ARPHRD_IEEE80211; + net_dev->type = ARPHRD_IEEE80211; else - bcm->net_dev->type = ARPHRD_ETHER; + net_dev->type = ARPHRD_ETHER; - if (!bcm->initialized) - return; - - bcm43xx_mac_suspend(bcm); status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Reset status to infrastructured mode */ status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); - /*FIXME: We actually set promiscuous mode as well, until we don't - * get the HW mac filter working */ - status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC; + status &= ~BCM43xx_SBF_MODE_PROMISC; + status |= BCM43xx_SBF_MODE_NOTADHOC; + +/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ +status |= BCM43xx_SBF_MODE_PROMISC; switch (iw_mode) { case IW_MODE_MONITOR: - status |= (BCM43xx_SBF_MODE_PROMISC | - BCM43xx_SBF_MODE_MONITOR); + status |= BCM43xx_SBF_MODE_MONITOR; + status |= BCM43xx_SBF_MODE_PROMISC; break; case IW_MODE_ADHOC: status &= ~BCM43xx_SBF_MODE_NOTADHOC; break; case IW_MODE_MASTER: + status |= BCM43xx_SBF_MODE_AP; + break; case IW_MODE_SECOND: case IW_MODE_REPEAT: - /* TODO: No AP/Repeater mode for now :-/ */ - TODO(); + TODO(); /* TODO */ break; case IW_MODE_INFRA: /* nothing to be done here... */ break; default: - printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode); + dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); } - + if (net_dev->flags & IFF_PROMISC) + status |= BCM43xx_SBF_MODE_PROMISC; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - bcm43xx_mac_enable(bcm); + + value = 0x0002; + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) + value = 0x0064; + else + value = 0x0032; + } + bcm43xx_write16(bcm, 0x0612, value); } /* This is the opposite of bcm43xx_chip_init() */ @@ -2357,7 +2367,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; - int iw_mode = bcm->ieee->iw_mode; int tmp; u32 value32; u16 value16; @@ -2411,20 +2420,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value32 |= BCM43xx_SBF_MODE_NOTADHOC; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - /*FIXME: For now, use promiscuous mode at all times; otherwise we don't - get broadcast or multicast packets */ - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= BCM43xx_SBF_MODE_PROMISC; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - if (iw_mode == IW_MODE_MONITOR) { - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= BCM43xx_SBF_MODE_PROMISC; - value32 |= BCM43xx_SBF_MODE_MONITOR; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - } value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; //FIXME: What's this? Is this correct? + value32 |= 0x100000; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); if (bcm43xx_using_pio(bcm)) { @@ -2439,13 +2437,8 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); - if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { - if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3)) - bcm43xx_write16(bcm, 0x0612, 0x0064); - else - bcm43xx_write16(bcm, 0x0612, 0x0032); - } else - bcm43xx_write16(bcm, 0x0612, 0x0002); + /* Initially set the wireless operation mode. */ + bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode); if (bcm->current_core->rev < 3) { bcm43xx_write16(bcm, 0x060E, 0x0000); -- cgit v1.2.3-70-g09d2 From 0ac59daee5f7fbaab25784a643edede669b5419e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Mar 2006 21:43:40 +0100 Subject: [PATCH] bcm43xx: some IRQ handler cleanups. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 65 +++++++++++++---------------- 1 file changed, 30 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a85176325e9..12c93d274ae 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1785,10 +1785,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } - /* We get spurious IRQs, althought they are masked. - * Assume they are void and ignore them. - */ - bcmirq_handled(~(bcm->irq_savedstate)); /* IRQ_PIO_WORKAROUND is handled in the top-half. */ bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); #ifdef CONFIG_BCM43XX_DEBUG @@ -1809,41 +1805,31 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_unlock_mmio(bcm, flags); } -static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, - u32 reason, u32 mask) +static void pio_irq_workaround(struct bcm43xx_private *bcm, + u16 base, int queueidx) { - bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) - & 0x0001dc00; - bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) - & 0x0000dc00; - bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) - & 0x0000dc00; - bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) - & 0x0001dc00; + u16 rxctl; + + rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); + if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) + bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; + else + bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE; +} +static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) +{ if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ - -#define apply_pio_workaround(BASE, QNUM) \ - do { \ - if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \ - bcm->dma_reason[QNUM] |= 0x00010000; \ - else \ - bcm->dma_reason[QNUM] &= ~0x00010000; \ - } while (0) - - apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0); - apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1); - apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2); - apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3); - -#undef apply_pio_workaround + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); } - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, - reason & mask); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, bcm->dma_reason[0]); @@ -1860,7 +1846,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re { irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; - u32 reason, mask; + u32 reason; if (!bcm) return IRQ_NONE; @@ -1873,11 +1859,20 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re ret = IRQ_NONE; goto out; } - mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - if (!(reason & mask)) + reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + if (!reason) goto out; - bcm43xx_interrupt_ack(bcm, reason, mask); + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) + & 0x0001dc00; + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) + & 0x0000dc00; + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) + & 0x0000dc00; + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) + & 0x0001dc00; + + bcm43xx_interrupt_ack(bcm, reason); /* Only accept IRQs, if we are initialized properly. * This avoids an RX race while initializing. -- cgit v1.2.3-70-g09d2 From 6ecb26904c9db15ca964d60b9483f19dc51bda5b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 20 Mar 2006 00:01:04 +0100 Subject: [PATCH] bcm43xx: set default attenuation values. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 21 +++-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 30 +++--- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 131 +++++++++++++++++++++++++-- drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 5 + 5 files changed, 158 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 8820012b4b3..1fca1f9c48f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -507,14 +507,23 @@ struct bcm43xx_radioinfo { u16 version; u8 revision; - /* 0: baseband attenuation, - * 1: radio attenuation, - * 2: tx_CTL1 - * 3: tx_CTL2 - */ - u16 txpower[4]; /* Desired TX power in dBm Q5.2 */ u16 txpower_desired; + /* TX Power control values. */ + union { + /* B/G PHY */ + struct { + u16 baseband_atten; + u16 radio_atten; + u16 txctl1; + u16 txctl2; + }; + /* A PHY */ + struct { + u16 txpwr_offset; + }; + }; + /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 12c93d274ae..e680d2acc44 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -560,12 +560,9 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->revision = revision; /* Set default attenuation values. */ - radio->txpower[0] = 2; - radio->txpower[1] = 2; - if (revision == 1) - radio->txpower[2] = 3; - else - radio->txpower[2] = 0; + radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); + radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); + radio->txctl1 = bcm43xx_default_txctl1(bcm); if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 1ce9a459990..054c64e462f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -220,9 +220,9 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); } else { - saved_batt = radio->txpower[0]; - saved_ratt = radio->txpower[1]; - saved_txctl1 = radio->txpower[2]; + saved_batt = radio->baseband_atten; + saved_ratt = radio->radio_atten; + saved_txctl1 = radio->txctl1; if ((radio->revision >= 6) && (radio->revision <= 8) && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); @@ -1039,7 +1039,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0078, radio->initval); bcm43xx_radio_write16(bcm, 0x0052, (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) - | radio->txpower[3]); + | radio->txctl2); } if (phy->connected) { @@ -1259,7 +1259,6 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, if (baseband_attenuation > 6) baseband_attenuation = 6; assert(radio_attenuation < 10); - assert(tx == 0 || tx == 3); if (tx == 3) { return bcm43xx_get_lopair(phy, @@ -1275,9 +1274,9 @@ struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); return bcm43xx_find_lopair(bcm, - radio->txpower[0], - radio->txpower[1], - radio->txpower[2]); + radio->baseband_atten, + radio->radio_atten, + radio->txctl1); } /* Adjust B/G LO */ @@ -1311,7 +1310,7 @@ static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) txctl2 = i; } } - radio->txpower[3] = txctl2; + radio->txctl2 = txctl2; } static @@ -1530,8 +1529,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) r31 = 0; } bcm43xx_radio_write16(bcm, 0x43, i); - bcm43xx_radio_write16(bcm, 0x52, - radio->txpower[3]); + bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); udelay(10); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); @@ -1573,7 +1571,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) } bcm43xx_radio_write16(bcm, 0x43, i - 9); bcm43xx_radio_write16(bcm, 0x52, - radio->txpower[3] + radio->txctl2 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? udelay(10); @@ -1780,9 +1778,9 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } /* Calculate the new attenuation values. */ - baseband_attenuation = radio->txpower[0]; + baseband_attenuation = radio->baseband_atten; baseband_attenuation += baseband_att_delta; - radio_attenuation = radio->txpower[1]; + radio_attenuation = radio->radio_atten; radio_attenuation += radio_att_delta; /* Get baseband and radio attenuation values into their permitted ranges. @@ -1807,7 +1805,7 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - txpower = radio->txpower[2]; + txpower = radio->txctl1; if ((radio->version == 0x2050) && (radio->revision == 2)) { if (radio_attenuation <= 1) { if (txpower == 0) { @@ -1829,7 +1827,7 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } } } - radio->txpower[2] = txpower; + radio->txctl1 = txpower; baseband_attenuation = limit_value(baseband_attenuation, 0, 11); radio_attenuation = limit_value(radio_attenuation, 0, 9); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index cac604bc095..4e8d8c936ab 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1652,7 +1652,7 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) bcm43xx_ilt_write(bcm, 0x3001, dac); - radio->txpower[0] = txpower; + radio->txpwr_offset = txpower; TODO(); //TODO: FuncPlaceholder (Adjust BB loft cancel) @@ -1666,17 +1666,14 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation == 0xFFFF) - baseband_attenuation = radio->txpower[0]; - else - radio->txpower[0] = baseband_attenuation; + baseband_attenuation = radio->baseband_atten; if (radio_attenuation == 0xFFFF) - radio_attenuation = radio->txpower[1]; - else - radio->txpower[1] = radio_attenuation; + radio_attenuation = radio->radio_atten; if (txpower == 0xFFFF) - txpower = radio->txpower[2]; - else - radio->txpower[2] = txpower; + txpower = radio->txctl1; + radio->baseband_atten = baseband_attenuation; + radio->radio_atten = radio_attenuation; + radio->txctl1 = txpower; assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); if (radio->revision < 6) @@ -1693,10 +1690,124 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) | ((txpower << 4) & 0x0070)); } + //FIXME: The spec is very weird and unclear here. if (phy->type == BCM43xx_PHYTYPE_G) bcm43xx_phy_lo_adjust(bcm, 0); } +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version == 0x2050 && radio->revision < 6) + return 0; + return 2; +} + +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 att = 0xFFFF; + + if (phy->type == BCM43xx_PHYTYPE_A) + return 0x60; + + switch (radio->version) { + case 0x2053: + switch (radio->revision) { + case 1: + att = 6; + break; + } + break; + case 0x2050: + switch (radio->revision) { + case 0: + att = 5; + break; + case 1: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 3; + else + att = 1; + } else { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 7; + else + att = 6; + } + break; + case 2: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 5; + else if (bcm->chip_id == 0x4320) + att = 4; + else + att = 3; + } else + att = 6; + break; + case 3: + att = 5; + break; + case 4: + case 5: + att = 1; + break; + case 6: + case 7: + att = 5; + break; + case 8: + att = 0x1A; + break; + case 9: + default: + att = 5; + } + } + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421) { + if (bcm->board_revision < 0x43) + att = 2; + else if (bcm->board_revision < 0x51) + att = 3; + } + if (att == 0xFFFF) + att = 5; + + return att; +} + +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version != 0x2050) + return 0; + if (radio->revision == 1) + return 3; + if (radio->revision < 6) + return 2; + if (radio->revision == 8) + return 1; + return 0; +} void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index a5d2e10d5d9..9ed18039fa3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -72,6 +72,11 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, u16 baseband_attenuation, u16 attenuation, u16 txpower); + +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm); + void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); -- cgit v1.2.3-70-g09d2 From e382c234cbc6fcd76e9ed1168c77fe88d75df73c Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Mar 2006 18:16:28 +0100 Subject: [PATCH] bcm43xx: sync interference mitigation code to the specs. This also includes a rewritten valuesave-stack. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 12 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 447 ++++++++++++++++++--------- 2 files changed, 309 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 1fca1f9c48f..57fcaafcf7d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -526,8 +526,16 @@ struct bcm43xx_radioinfo { /* Current Interference Mitigation mode */ int interfmode; - /* Stack of saved values from the Interference Mitigation code */ - u16 interfstack[20]; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define BCM43xx_INTERFSTACK_SIZE 26 + u32 interfstack[BCM43xx_INTERFSTACK_SIZE]; + /* Saved values from the NRSSI Slope calculation */ s16 nrssi[2]; s32 nrssislope; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 4e8d8c936ab..63aae43ba83 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -879,24 +879,76 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) } } -/* Helper macros to save on and restore values from the radio->interfstack */ -#ifdef stack_save -# undef stack_save -#endif -#ifdef stack_restore -# undef stack_restore -#endif -#define stack_save(value) \ +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 *_stackptr, size_t *stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + *stackptr = offset; + *stackptr |= ((u32)id) << 12; + *stackptr |= ((u32)value) << 16; + (*stackidx)++; + assert(*stackidx < BCM43xx_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 *stackptr, + u8 id, u16 offset) +{ + size_t i; + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + assert(0); + + return 0; +} + +#define phy_stacksave(offset) \ do { \ - assert(i < ARRAY_SIZE(radio->interfstack)); \ - stack[i++] = (value); \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + bcm43xx_phy_read(bcm, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + bcm43xx_phy_write(bcm, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + bcm43xx_radio_read16(bcm, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + bcm43xx_radio_write16(bcm, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ilt_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset), \ + bcm43xx_ilt_read(bcm, (offset))); \ + } while (0) +#define ilt_stackrestore(offset) \ + do { \ + bcm43xx_ilt_write(bcm, (offset), \ + _stack_restore(stack, 0x3, \ + (offset))); \ } while (0) - -#define stack_restore() \ - ({ \ - assert(i < ARRAY_SIZE(radio->interfstack)); \ - stack[i++]; \ - }) static void bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, @@ -904,144 +956,231 @@ bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int i = 0; - u16 *stack = radio->interfstack; u16 tmp, flipped; + u32 tmp32; + size_t stackidx = 0; + u32 *stack = radio->interfstack; switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONWLAN: if (phy->rev != 1) { bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) & 0x0800); + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); break; } + radio_stacksave(0x0078); tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); flipped = flip_4bit(tmp); - if ((flipped >> 1) >= 4) - tmp = flipped - 3; - tmp = flip_4bit(tmp); - bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + bcm43xx_radio_write16(bcm, 0x0078, flipped); bcm43xx_calc_nrssi_threshold(bcm); - if (bcm->current_core->rev < 5) { - stack_save(bcm43xx_phy_read(bcm, 0x0406)); - bcm43xx_phy_write(bcm, 0x0406, 0x7E28); - } else { - stack_save(bcm43xx_phy_read(bcm, 0x04C0)); - stack_save(bcm43xx_phy_read(bcm, 0x04C1)); - bcm43xx_phy_write(bcm, 0x04C0, 0x3E04); - bcm43xx_phy_write(bcm, 0x04C1, 0x0640); - } + phy_stacksave(0x0406); + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); - stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + phy_stacksave(0x04A0); bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); - stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + phy_stacksave(0x04A1); bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); - stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + phy_stacksave(0x04A2); bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); - stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + phy_stacksave(0x04A8); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403); - stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504); + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605); - stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + phy_stacksave(0x04A7); bcm43xx_phy_write(bcm, 0x04A7, 0x0002); - stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + phy_stacksave(0x04A3); bcm43xx_phy_write(bcm, 0x04A3, 0x287A); - stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + phy_stacksave(0x04A9); bcm43xx_phy_write(bcm, 0x04A9, 0x2027); - stack_save(bcm43xx_phy_read(bcm, 0x0493)); + phy_stacksave(0x0493); bcm43xx_phy_write(bcm, 0x0493, 0x32F5); - stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + phy_stacksave(0x04AA); bcm43xx_phy_write(bcm, 0x04AA, 0x2027); - stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + phy_stacksave(0x04AC); bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); break; case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800) + if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800) break; radio->aci_enable = 1; - stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)); - stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)); - if (bcm->current_core->rev < 5) { - stack_save(bcm43xx_phy_read(bcm, 0x0406)); + phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD); + phy_stacksave(BCM43xx_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); } else { - stack_save(bcm43xx_phy_read(bcm, 0x04C0)); - stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); } - stack_save(bcm43xx_phy_read(bcm, 0x0033)); - stack_save(bcm43xx_phy_read(bcm, 0x04A7)); - stack_save(bcm43xx_phy_read(bcm, 0x04A3)); - stack_save(bcm43xx_phy_read(bcm, 0x04A9)); - stack_save(bcm43xx_phy_read(bcm, 0x04AA)); - stack_save(bcm43xx_phy_read(bcm, 0x04AC)); - stack_save(bcm43xx_phy_read(bcm, 0x0493)); - stack_save(bcm43xx_phy_read(bcm, 0x04A1)); - stack_save(bcm43xx_phy_read(bcm, 0x04A0)); - stack_save(bcm43xx_phy_read(bcm, 0x04A2)); - stack_save(bcm43xx_phy_read(bcm, 0x048A)); - stack_save(bcm43xx_phy_read(bcm, 0x04A8)); - stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ilt_stacksave(0x1A00 + 0x2); + ilt_stacksave(0x1A00 + 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF); + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~0x1000); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002); + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) + & 0xFFFC) | 0x0002); - bcm43xx_phy_write(bcm, 0x04A7, 0x0800); - bcm43xx_phy_write(bcm, 0x04A3, 0x287A); - bcm43xx_phy_write(bcm, 0x04A9, 0x2027); - bcm43xx_phy_write(bcm, 0x0493, 0x32F5); - bcm43xx_phy_write(bcm, 0x04AA, 0x2027); - bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + bcm43xx_phy_write(bcm, 0x0033, 0x0800); + bcm43xx_phy_write(bcm, 0x04A3, 0x2027); + bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8); + bcm43xx_phy_write(bcm, 0x0493, 0x287A); + bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8); + bcm43xx_phy_write(bcm, 0x04AC, 0x287A); bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A); - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, 0x280D); - } else { - bcm43xx_phy_write(bcm, 0x04C0, 0x0640); + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xFFC0) | 0x001A); + bcm43xx_phy_write(bcm, 0x04A7, 0x000D); + + if (phy->rev < 2) { + bcm43xx_phy_write(bcm, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF); bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); + } else { + bcm43xx_phy_write(bcm, 0x04C0, 0x00C1); + bcm43xx_phy_write(bcm, 0x04C1, 0x0059); } bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800); + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xC0FF) | 0x1800); bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900); - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D); + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xFFC0) | 0x0015); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000); + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xCFFF) | 0x1000); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00); + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xF0FF) | 0x0A00); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xCFFF) | 0x1000); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xF0FF) | 0x0800); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFCF) | 0x0010); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFF0) | 0x0005); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFF0) | 0x0006); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xF0FF) | 0x0500); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xFFF0) | 0x000B); + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + & ~0x8000); + bcm43xx_phy_write(bcm, 0x0415, + (bcm43xx_phy_read(bcm, 0x0415) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0416, + (bcm43xx_phy_read(bcm, 0x0416) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0417, + (bcm43xx_phy_read(bcm, 0x0417) + & 0xFE00) | 0x016D); + } else { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + | 0x1000); + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0x9FFF) | 0x2000); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (!(tmp32 & 0x800)) { + tmp32 |= 0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); + } + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) + | 0x0800); + } + bcm43xx_phy_write(bcm, 0x048C, + (bcm43xx_phy_read(bcm, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04AE, + (bcm43xx_phy_read(bcm, 0x04AE) + & 0xFF00) | 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F); + bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF); + } bcm43xx_calc_nrssi_slope(bcm); break; default: @@ -1055,9 +1194,8 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int i = 0; - u16 *stack = radio->interfstack; - u16 tmp, flipped; + u32 tmp32; + u32 *stack = radio->interfstack; switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONWLAN: @@ -1065,71 +1203,80 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); break; } - tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); - if ((flipped >> 1) >= 0x000C) - tmp = flipped + 3; - tmp = flip_4bit(tmp); - bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); - + phy_stackrestore(0x0078); bcm43xx_calc_nrssi_threshold(bcm); - - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, stack_restore()); - } else { - bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); - } + phy_stackrestore(0x0406); bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); - - if (!bcm->bad_frames_preempt) + if (!bcm->bad_frames_preempt) { bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11)); + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); - bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); - bcm43xx_phy_write(bcm, 0x0493, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); break; case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800) + if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800)) break; radio->aci_enable = 0; - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore()); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore()); - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, stack_restore()); - } else { - bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD); + phy_stackrestore(BCM43xx_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ilt_stackrestore(0x1A00 + 0x2); + ilt_stackrestore(0x1A00 + 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (tmp32 & 0x800) { + tmp32 &= ~0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); } - bcm43xx_phy_write(bcm, 0x0033, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); - bcm43xx_phy_write(bcm, 0x0493, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); - bcm43xx_calc_nrssi_slope(bcm); break; default: @@ -1137,8 +1284,12 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, } } -#undef stack_save -#undef stack_restore +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ilt_stacksave +#undef ilt_stackrestore int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode) -- cgit v1.2.3-70-g09d2 From cf017e1b6f625978288e2cd8ede04f8185b97c08 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 22 Mar 2006 17:58:47 +0100 Subject: [PATCH] bcm43xx: fix nrssi_threshold calculation. patch by doctorzoidberg. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 72 +++++++++++++--------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 63aae43ba83..af5c0bff169 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -782,41 +782,30 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - s16 threshold; + s32 threshold; s32 a, b; - int tmp; s16 tmp16; u16 tmp_u16; switch (phy->type) { case BCM43xx_PHYTYPE_B: { - int radiotype = 0; - - if (phy->rev < 2) - return; if (radio->version != 0x2050) return; if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) return; - tmp = radio->revision; - if ((radio->manufact == 0x175 && tmp == 5) || - (radio->manufact == 0x17F && (tmp == 3 || tmp == 4))) - radiotype = 1; - - if (radiotype == 1) { + if (radio->revision >= 6) { + threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32; + threshold += 20 * (radio->nrssi[0] + 1); + threshold /= 40; + } else threshold = radio->nrssi[1] - 5; - } else { - threshold = 40 * radio->nrssi[0]; - threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); - threshold += 20; - threshold /= 10; - } + threshold = limit_value(threshold, 0, 0x3E); bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); - if (radiotype == 1) { + if (radio->revision >= 6) { bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); bcm43xx_phy_write(bcm, 0x0085, 0x0A09); @@ -844,33 +833,38 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) & 0xF000) | 0x0AED); } } else { - tmp = radio->interfmode; - if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) { - a = -13; - b = -17; - } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE && - !radio->aci_enable) { - a = -13; - b = -10; + if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!radio->aci_wlan_automatic && radio->aci_enable) { + a = 0x13; + b = 0x12; } else { - a = -8; - b = -9; + a = 0xE; + b = 0x11; } - a += 0x1B; - a *= radio->nrssi[1] - radio->nrssi[0]; - a += radio->nrssi[0] * 0x40; - a /= 64; - b += 0x1B; - b *= radio->nrssi[1] - radio->nrssi[0]; - b += radio->nrssi[0] * 0x40; - b /= 64; + a = a * (radio->nrssi[1] - radio->nrssi[0]); + a += (radio->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; a = limit_value(a, -31, 31); + + b = b * (radio->nrssi[1] - radio->nrssi[0]); + b += (radio->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; b = limit_value(b, -31, 31); tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; - tmp_u16 |= ((u32)a & 0x003F); - tmp_u16 |= (((u32)b & 0x003F) << 6); + tmp_u16 |= ((u32)b & 0x0000003F); + tmp_u16 |= (((u32)a & 0x0000003F) << 6); bcm43xx_phy_write(bcm, 0x048A, tmp_u16); } break; -- cgit v1.2.3-70-g09d2 From 72fb851e971a416f47ad0a3ffca7342a424af37a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 22 Mar 2006 18:10:19 +0100 Subject: [PATCH] bcm43xx: add useless and broken statistics stuff. People seem to want it. well... Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 2 ++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 3 ++ drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 52 ++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 57fcaafcf7d..ae0fe5cf1d4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -621,6 +621,8 @@ struct bcm43xx_noise_calculation { struct bcm43xx_stats { u8 link_quality; + u8 noise; + struct iw_statistics wstats; /* Store the last TX/RX times here for updating the leds. */ unsigned long last_tx; unsigned long last_rx; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e680d2acc44..15deaa508e5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1539,6 +1539,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) average *= 125; average += 64; average /= 128; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); tmp = (tmp / 128) & 0x1F; if (tmp >= 8) @@ -1550,6 +1551,8 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) else average -= 48; +/* FIXME: This is wrong, but people want fancy stats. well... */ +bcm->stats.noise = average; if (average > -65) bcm->stats.link_quality = 0; else if (average > -75) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 651ba605495..e9296340285 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -244,13 +244,13 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->max_qual.qual = 100; /* TODO: Real max RSSI */ - range->max_qual.level = 0; - range->max_qual.noise = 0; + range->max_qual.level = 3; + range->max_qual.noise = 100; range->max_qual.updated = 7; range->avg_qual.qual = 70; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; + range->avg_qual.level = 2; + range->avg_qual.noise = 40; range->avg_qual.updated = 7; range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; @@ -875,6 +875,49 @@ out: return err; } +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ + +static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); + struct iw_statistics *wstats; + + wstats = &bcm->stats.wstats; + if (!mac->associated) { + wstats->miss.beacon = 0; +// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? + wstats->discard.retries = 0; +// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question + wstats->discard.nwid = 0; +// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto + wstats->discard.code = 0; +// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here + wstats->discard.fragment = 0; + wstats->discard.misc = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + return wstats; + } + /* fill in the real statistics when iface associated */ + wstats->qual.qual = 100; // TODO: get the real signal quality + wstats->qual.level = 3 - bcm->stats.link_quality; + wstats->qual.noise = bcm->stats.noise; + wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED; + wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; + wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; + wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; + wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; + wstats->discard.misc = 0; // FIXME + wstats->miss.beacon = 0; // FIXME + return wstats; +} + #ifdef WX # undef WX @@ -1010,6 +1053,7 @@ const struct iw_handler_def bcm43xx_wx_handlers_def = { .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), .private = bcm43xx_priv_wx_handlers, .private_args = bcm43xx_priv_wx_args, + .get_wireless_stats = bcm43xx_get_wireless_stats, }; /* vim: set ts=8 sw=8 sts=8: */ -- cgit v1.2.3-70-g09d2 From 04b98f71e2e3facc15e73b7e3ae9516ecb737375 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 15:37:53 +0100 Subject: [PATCH] bcm43xx: get rid of "/* vim: ..." lines at the end of several files. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 2 -- 8 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index f73d36b8e0f..d2c3401e9b7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -497,5 +497,3 @@ void bcm43xx_printk_bitdump(const unsigned char *data, } printk("\n"); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 9c64438b767..18928acedd7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -968,5 +968,3 @@ void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) & ~BCM43xx_DMA_TXCTRL_SUSPEND); bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index c8f5ad75d2a..4b2c02c0b31 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -291,5 +291,3 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 15deaa508e5..281db642bd5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3956,5 +3956,3 @@ static void __exit bcm43xx_exit(void) module_init(bcm43xx_init) module_exit(bcm43xx_exit) - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 5b6f0a84d01..c59ddd40680 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -604,5 +604,3 @@ data_ready: } bcm43xx_rx(queue->bcm, skb, rxhdr); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 35c3c9704c3..c44d890b949 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -320,5 +320,3 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) device_remove_file(dev, &sysfs->attr_interfmode); device_remove_file(dev, &sysfs->attr_sprom); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index e9296340285..e72be32bda7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -1055,5 +1055,3 @@ const struct iw_handler_def bcm43xx_wx_handlers_def = { .private_args = bcm43xx_priv_wx_args, .get_wireless_stats = bcm43xx_get_wireless_stats, }; - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index c4809da8e9c..9c37478c80d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -577,5 +577,3 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, return err; } - -/* vim: set ts=8 sw=8 sts=8: */ -- cgit v1.2.3-70-g09d2 From d1ca6c4ff6714826acb1a434e5d3862984eb26d5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 15:43:18 +0100 Subject: [PATCH] bcm43xx: fix "include" issues on some platforms. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 3 +-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 18928acedd7..bad5374b81b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -34,11 +34,10 @@ #include "bcm43xx_power.h" #include "bcm43xx_xmit.h" -#include +#include #include #include #include -#include static inline int free_slots(struct bcm43xx_dmaring *ring) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 281db642bd5..29df4f844c9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "bcm43xx.h" -- cgit v1.2.3-70-g09d2 From b5e868edbeaa5fd832d42563195c0da00edfd3c9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 16:27:32 +0100 Subject: [PATCH] bcm43xx: remove some compilerwarnings. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1 - drivers/net/wireless/bcm43xx/bcm43xx_main.c | 10 ++++-- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 55 ----------------------------- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 7 ++-- 4 files changed, 13 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index bad5374b81b..c3681b8f09b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -787,7 +787,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status) { - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 29df4f844c9..ac9a8dd1ab8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -404,6 +404,8 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); } +//FIXME: Well, we should probably call them from somewhere. +#if 0 static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ @@ -422,8 +424,12 @@ static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 20); } +#endif -//FIXME: rename this func? +/* FIXME: To get the MAC-filter working, we need to implement the + * following functions (and rename them :) + */ +#if 0 static void bcm43xx_disassociate(struct bcm43xx_private *bcm) { bcm43xx_mac_suspend(bcm); @@ -451,7 +457,6 @@ static void bcm43xx_disassociate(struct bcm43xx_private *bcm) bcm43xx_mac_enable(bcm); } -//FIXME: rename this func? static void bcm43xx_associate(struct bcm43xx_private *bcm, const u8 *mac) { @@ -462,6 +467,7 @@ static void bcm43xx_associate(struct bcm43xx_private *bcm, bcm43xx_write_mac_bssid_templates(bcm); bcm43xx_mac_enable(bcm); } +#endif /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. * Returns the _previously_ enabled IRQ mask. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index e72be32bda7..3daee828ef4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -106,7 +106,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct ieee80211softmac_device *softmac = bcm->softmac; unsigned long flags; u8 channel; int freq; @@ -205,24 +204,6 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, return 0; } -static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, @@ -517,24 +498,6 @@ out_unlock: return err; } -static int bcm43xx_wx_set_retry(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_retry(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_set_encoding(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, @@ -587,24 +550,6 @@ static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, return err; } -static int bcm43xx_wx_set_power(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_power(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 9c37478c80d..d8ece28c079 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -215,7 +215,7 @@ static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, u8 fallback_bitrate; int ofdm_modulation; int fallback_ofdm_modulation; - u8 *sa, *da; +// u8 *sa, *da; u16 flen; //FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); @@ -267,7 +267,7 @@ assert(dur); //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! - memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); +// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); *flags |= BCM43xx_TXHDRFLAG_RTSCTS; *flags |= BCM43xx_TXHDRFLAG_RTS; @@ -439,6 +439,8 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, return (s8)tmp; } +//TODO +#if 0 static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) { @@ -453,6 +455,7 @@ static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, return ret; } +#endif int bcm43xx_rx(struct bcm43xx_private *bcm, struct sk_buff *skb, -- cgit v1.2.3-70-g09d2 From 8afceb1e6a3b6361c7c2456ef488ee9c6db7b370 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 17:04:41 +0100 Subject: [PATCH] bcm43xx: fix the remaining sparse warnings. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 ++-- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index ac9a8dd1ab8..7c1d72fc628 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2509,7 +2509,7 @@ error: return -ENODEV; } -void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) +static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) { /* Initialize a "phyinfo" structure. The structure is already * zeroed out. @@ -2521,7 +2521,7 @@ void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) spin_lock_init(&phy->lock); } -void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) +static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) { /* Initialize a "radioinfo" structure. The structure is already * zeroed out. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 054c64e462f..4ab17a7f7e9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1057,9 +1057,14 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x002F, 0x0202); } - if ((bcm->sprom.boardflags & BCM43xx_BFL_RSSI) == 0) { - FIXME();//FIXME: 0x7FFFFFFF should be 16-bit ! - bcm43xx_nrssi_hw_update(bcm, (u16)0x7FFFFFFF); + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + bcm43xx_nrssi_hw_update(bcm, 0xFFFF); bcm43xx_calc_nrssi_threshold(bcm); } else if (phy->connected) { if (radio->nrssi[0] == -1000) { -- cgit v1.2.3-70-g09d2 From adc40e9796d03d56e99bdac62492492a1098124b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 20:36:57 +0100 Subject: [PATCH] bcm43xx: sync GPHY init with the specs. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 5 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 275 +++++++++++++++++++++++++--- 3 files changed, 255 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index ae0fe5cf1d4..dcadd295de4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -495,6 +495,10 @@ struct bcm43xx_phyinfo { const s8 *tssi2dbm; /* idle TSSI value */ s8 idle_tssi; + + /* Values from bcm43xx_calc_loopback_gain() */ + u16 loopback_gain[2]; + /* PHY lock for core.rev < 3 * This lock is only used by bcm43xx_phy_{un}lock() */ @@ -674,6 +678,7 @@ struct bcm43xx_private { u16 chip_id; u8 chip_rev; + u8 chip_package; struct bcm43xx_sprominfo sprom; #define BCM43xx_NR_LEDS 4 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 7c1d72fc628..2b7ef9b46cc 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -570,6 +570,7 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); radio->txctl1 = bcm43xx_default_txctl1(bcm); + radio->txctl2 = 0xFFFF; if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else @@ -2635,7 +2636,8 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) } bcm->chip_id = chip_id_16; - bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16; + bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16; + bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20; dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", bcm->chip_id, bcm->chip_rev); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 4ab17a7f7e9..0a66f43ca0c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -994,12 +994,205 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x03E6, 0x0); } +static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 backup_phy[15]; + u16 backup_radio[3]; + u16 backup_bband; + u16 i; + u16 loop1_cnt, loop1_done, loop1_omitted; + u16 loop2_done; + + backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429); + backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001); + backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811); + backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812); + backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814); + backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815); + backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A); + backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059); + backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058); + backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A); + backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003); + backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F); + backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810); + backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B); + backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015); + bcm43xx_phy_read(bcm, 0x002D); /* dummy read */ + backup_bband = radio->baseband_atten; + backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052); + backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043); + backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF); + bcm43xx_phy_write(bcm, 0x0001, + bcm43xx_phy_read(bcm, 0x0001) & 0x8000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0002); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0001); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0002); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) + & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xFFCF) | 0x0010); + + bcm43xx_phy_write(bcm, 0x005A, 0x0780); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->version == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + if (radio->version == 0x2050 && radio->revision == 2) { + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0xFFF0) | 0x0009); + loop1_cnt = 9; + } else if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x000F); + loop1_cnt = 15; + } else + loop1_cnt = 0; + + bcm43xx_phy_set_baseband_attenuation(bcm, 11); + + if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x080F, 0xC020); + else + bcm43xx_phy_write(bcm, 0x080F, 0x8020); + bcm43xx_phy_write(bcm, 0x0810, 0x0000); + + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xFFC0) | 0x0001); + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xC0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0100); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { + if (phy->rev >= 7) { + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) + | 0x0800); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x8000); + } + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + & 0x00F7); + + for (i = 0; i < loop1_cnt; i++) { + bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + loop1_done = i; + loop1_omitted = loop1_cnt - loop1_done; + + loop2_done = 0; + if (loop1_done >= 8) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x0030); + for (i = loop1_done - 8; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + } + + bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]); + bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]); + bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]); + bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]); + bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]); + bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]); + bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]); + bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]); + bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]); + bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]); + bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]); + + bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband); + + bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]); + bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]); + bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]); + + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003); + udelay(10); + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]); + bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]); + bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]); + bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]); + + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; +} + static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; - + if (phy->rev == 1) bcm43xx_phy_initb5(bcm); else if (phy->rev >= 2 && phy->rev <= 7) @@ -1015,47 +1208,63 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) else if (phy->rev >= 3) bcm43xx_phy_write(bcm, 0x0811, 0x0400); bcm43xx_phy_write(bcm, 0x0015, 0x00C0); - tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; - if (tmp == 3) { - bcm43xx_phy_write(bcm, 0x04C2, 0x1816); - bcm43xx_phy_write(bcm, 0x04C3, 0x8606); - } else if (tmp == 4 || tmp == 5) { - bcm43xx_phy_write(bcm, 0x04C2, 0x1816); - bcm43xx_phy_write(bcm, 0x04C3, 0x8006); - bcm43xx_phy_write(bcm, 0x04CC, (bcm43xx_phy_read(bcm, 0x04CC) - & 0x00FF) | 0x1F00); + if (phy->connected) { + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; + if (tmp < 6) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); + if (tmp != 3) { + bcm43xx_phy_write(bcm, 0x04CC, + (bcm43xx_phy_read(bcm, 0x04CC) + & 0x00FF) | 0x1F00); + } + } } } - if (radio->revision <= 3 && phy->connected) + if (phy->rev < 3 && phy->connected) bcm43xx_phy_write(bcm, 0x047E, 0x0078); - if (radio->revision >= 6 && radio->revision <= 8) { + if (phy->rev >= 6 && phy->rev <= 8) { bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); } - if (radio->initval == 0xFFFF) { - radio->initval = bcm43xx_radio_init2050(bcm); + if (phy->rev >= 2 && phy->connected) + bcm43xx_calc_loopback_gain(bcm); + if (radio->revision != 8) { + if (radio->initval == 0xFFFF) + radio->initval = bcm43xx_radio_init2050(bcm); + else + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); + } + if (radio->txctl2 == 0xFFFF) { bcm43xx_phy_lo_g_measure(bcm); } else { - bcm43xx_radio_write16(bcm, 0x0078, radio->initval); - bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) - | radio->txctl2); - } - - if (phy->connected) { - bcm43xx_phy_lo_adjust(bcm, 0); - bcm43xx_phy_write(bcm, 0x080F, 0x8078); - + if (radio->version == 0x2050 && radio->revision == 8) { + //FIXME + } else { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) + & 0xFFF0) | radio->txctl1); + } + if (phy->rev >= 6) { + /* + bcm43xx_phy_write(bcm, 0x0036, + (bcm43xx_phy_read(bcm, 0x0036) + & 0xF000) | (FIXME << 12)); + */ + } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) - bcm43xx_phy_write(bcm, 0x002E, 0x807F); - else bcm43xx_phy_write(bcm, 0x002E, 0x8075); - + else + bcm43xx_phy_write(bcm, 0x003E, 0x807F); if (phy->rev < 2) bcm43xx_phy_write(bcm, 0x002F, 0x0101); else bcm43xx_phy_write(bcm, 0x002F, 0x0202); } + if (phy->connected) { + bcm43xx_phy_lo_adjust(bcm, 0); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + } if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { /* The specs state to update the NRSSI LT with @@ -1070,10 +1279,20 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) if (radio->nrssi[0] == -1000) { assert(radio->nrssi[1] == -1000); bcm43xx_calc_nrssi_slope(bcm); - } else + } else { + assert(radio->nrssi[1] != -1000); bcm43xx_calc_nrssi_threshold(bcm); + } } + if (radio->revision == 8) + bcm43xx_phy_write(bcm, 0x0805, 0x3230); bcm43xx_phy_init_pctl(bcm); + if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); + bcm43xx_phy_write(bcm, 0x04C3, + bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF); + } } static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) -- cgit v1.2.3-70-g09d2 From ec483781fe98bba92e00f4428f8d69dd5e071246 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 27 Mar 2006 11:49:51 +0200 Subject: [PATCH] bcm43xx: don't set the channel on a device, which is down. Initial patch by David Woodhouse and Michael Marineau. Locking fix by me. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 2b7ef9b46cc..c37371fc9e0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3530,12 +3530,18 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, u8 channel) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; bcm43xx_lock_mmio(bcm, flags); - bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_mac_enable(bcm); + if (bcm->initialized) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else { + radio = bcm43xx_current_radio(bcm); + radio->initial_channel = channel; + } bcm43xx_unlock_mmio(bcm, flags); } -- cgit v1.2.3-70-g09d2 From e4a9af98bb0fab13be6e3adbe108d565b790158a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 24 Mar 2006 17:56:19 +0100 Subject: [PATCH] PCMCIA_SPECTRUM must select FW_LOADER PCMCIA_SPECTRUM must select FW_LOADER. Reported by "Alexander E. Patrakov" . Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9c01fb26c8f..f85e3019000 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -404,6 +404,7 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" depends on NET_RADIO && PCMCIA && HERMES + select FW_LOADER ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol -- cgit v1.2.3-70-g09d2 From 0073602544954002e35699477dc59cdd5e9112e3 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 24 Mar 2006 16:45:24 -0800 Subject: [PATCH] zd1201 wireless stat update The "dev->get_wireless_stats" field is deprecated and slowly be surely going away. Most drivers have been updated months ago. Actually, there is an annoying message for driver still using it, but it seems that user of zd1201 were not annoyed enough ;-) Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/usb/net/zd1201.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index fe9b60cd8d9..9b1e4ed1d07 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -1736,6 +1736,7 @@ static const struct iw_handler_def zd1201_iw_handlers = { .standard = (iw_handler *)zd1201_iw_handler, .private = (iw_handler *)zd1201_private_handler, .private_args = (struct iw_priv_args *) zd1201_private_args, + .get_wireless_stats = zd1201_get_wireless_stats, }; static int zd1201_probe(struct usb_interface *interface, @@ -1796,7 +1797,6 @@ static int zd1201_probe(struct usb_interface *interface, zd->dev->open = zd1201_net_open; zd->dev->stop = zd1201_net_stop; zd->dev->get_stats = zd1201_get_stats; - zd->dev->get_wireless_stats = zd1201_get_wireless_stats; zd->dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; zd->dev->hard_start_xmit = zd1201_hard_start_xmit; -- cgit v1.2.3-70-g09d2 From 79058acaf5b6d4bcc3056382619de3ca9cebc62f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Mar 2006 21:24:54 -0800 Subject: [PATCH] hostap: Make hostap_tx_encrypt() static hostap_tx_encrypt() is used only inside hostap_80211_tx.c and there are no plans to use it elsewhere in the future either, so let's make it static. As a bonus, this should silence Coverity scanner from complaining about bogus FORWARD_NULL case (CID: 274). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_80211.h | 2 -- drivers/net/wireless/hostap/hostap_80211_tx.c | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 1fc72fe511e..cc1ee7f4f5f 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -92,8 +92,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt); int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); #endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 4a85e63906f..a881212e1fa 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -299,8 +299,8 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) +static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -317,7 +317,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, } if (local->tkip_countermeasures && - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + strcmp(crypt->ops->name, "TKIP") == 0) { hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " @@ -535,5 +535,4 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) EXPORT_SYMBOL(hostap_dump_tx_80211); -EXPORT_SYMBOL(hostap_tx_encrypt); EXPORT_SYMBOL(hostap_master_start_xmit); -- cgit v1.2.3-70-g09d2 From cfa146e4be274fd04bfdb26b3c96cdfe81a43dc2 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Mar 2006 21:24:55 -0800 Subject: [PATCH] hostap: Fix EAPOL frame encryption Fixed encrypted of EAPOL frames from wlan#ap interface (hostapd). This was broken when moving to use new frame control field defines in net/ieee80211.h. hostapd uses Protected flag, not protocol version (which was cleared in this function anyway). This fixes WPA group key handshake and re-authentication. http://hostap.epitest.fi/bugz/show_bug.cgi?id=126 Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_80211_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index a881212e1fa..06a5214145e 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -469,7 +469,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_VERS)) { + !(fc & IEEE80211_FCTL_PROTECTED)) { no_encrypt = 1; PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " "unencrypted EAPOL frame\n", dev->name); -- cgit v1.2.3-70-g09d2